选择角色

V0.1
yujialong 1 year ago
parent eea2542e90
commit 222946ce19
  1. 3
      .env
  2. 7
      src/api/system.ts
  3. BIN
      src/assets/images/panel/bg.png
  4. BIN
      src/assets/images/panel/btn.png
  5. BIN
      src/assets/images/panel/header.png
  6. BIN
      src/assets/images/panel/left.png
  7. BIN
      src/assets/images/panel/right.png
  8. BIN
      src/assets/images/role/1.png
  9. BIN
      src/assets/images/role/bg.png
  10. 149
      src/components/Panel/index.vue
  11. 14
      src/layout/index.vue
  12. 10
      src/router/index.ts
  13. 135
      src/views/Home.vue
  14. 171
      src/views/Role.vue

@ -2,6 +2,7 @@ VITE_APP_TITLE=金融产品设计及数字化营销沙盘
VITE_PORT=9520
VITE_PROXY=http://192.168.31.125:8080
VITE_PUBLIC_PATH=./
VITE_BASE_API=http://192.168.31.217:9000
#VITE_BASE_API=http://192.168.31.217:9000
VITE_BASE_API=http://121.37.12.51
VITE_I18N_LOCALE=zh-cn
VITE_I18N_FALLBACK_LOCALE=zh-cn

@ -1,8 +1,9 @@
import axios from '@/utils/request';
export const pageStuAssessment = async (data: Record<string, any>): Promise<any> => (await axios.post('/occupationlab/occupationlab/assessment/pageStuAssessment', data)).data;
export const getProjectBySystemId = async (data: Record<string, any>): Promise<any> =>
(await axios.get('/occupationlab/occupationlab/projectManage/getProjectBySystemId', data)).data;
export const getProjectDetail = async (data: Record<string, any>): Promise<any> => (await axios.get('/occupationlab/occupationlab/projectManage/getProjectDetail', data)).data;
export const getProjectBySystemId = async (params: Record<string, any>): Promise<any> =>
(await axios.get('/occupationlab/occupationlab/projectManage/getProjectBySystemId', { params })).data;
export const getProjectDetail = async (params: Record<string, any>): Promise<any> =>
(await axios.get('/occupationlab/occupationlab/projectManage/getProjectDetail', { params })).data;
export const getDetailById = async (id: number | string): Promise<any> => (await axios.get(`/occupationlab/occupationlab/assessment/getDetailById?id=${id}`)).data;
export const getCompetition = async (id: number | string): Promise<any> => (await axios.post(`/competition/competition/management/getCompetition?competitionId=${id}`)).data;

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

@ -8,7 +8,7 @@
<div class="panel-header"
id="panelHeader">
<div class="project">
<div class="inline-center">
<div class="inline-flex items-center">
<p>实训项目</p>
<el-tooltip effect="dark"
content="点击右侧“下三角”按钮可切换实验项目"
@ -21,8 +21,7 @@
placeholder="请选择"
class="select"
:disabled="per != 0"
@change="selectProject"
style="flex: 1">
@change="selectProject">
<el-option v-for="(item, i) in projectList"
:key="item.projectId"
:label="i + 1 + '. ' + item.projectName"
@ -57,7 +56,7 @@
<el-aside id="aside"
width="30%">
<div class="aside-header">
<div :class="['p-title color', 'system' + $themeId]">
<div class="p-title">
<i class="el-icon-s-order"></i>
<p>实验目标</p>
</div>
@ -77,7 +76,7 @@
</div>
</div>
<div class="aside-footer">
<div :class="['p-title color', 'system' + $themeId]">
<div class="p-title">
<i class="el-icon-s-management"></i>
<p>实验任务</p>
</div>
@ -195,20 +194,9 @@
</el-container>
</el-container>
<div :class="['toggle-panel', { active: visible }]"
id="toggle"
<div class="toggle-panel absolute w-[40px] h-[175px] bg-[url('@/assets/images/panel/right.png')] bg-[length:100%_100%] bg-no-repeat cursor-pointer"
:class="{ active: visible }"
@click="visible = !visible">
<!-- <div @click="togglePannel"> -->
<div>
<img :src="require(`@/assets/images/panel/left.png`)"
alt
class="c-p"
v-if="visible" />
<img :src="require(`@/assets/images/panel/right.png`)"
alt
class="c-p"
v-if="!visible" />
</div>
</div>
</div>
</template>
@ -226,9 +214,10 @@ import Setting from '@/setting';
const router = useRouter();
const route = useRoute();
const { systemId, classId, courseId, projectId, assessmentId, competitionId, stageId, teamId, mallId } = toRefs(route.query);
const projectId = ref<string | number>(+route.query.projectId);
const { systemId, classId, cid, assessmentId, competitionId, stageId, teamId, mallId } = toRefs(route.query);
const curSystemId = ref<number>(1);
const per = ref<number>(assessmentId.value ? 1 : competitionId.value ? 2 : 0); // (0 1 2)
const per = ref<number>(0); // (0 1 2)
const isSubmit = ref<boolean>(Cookie.get('st-isSubmit') === 'true'); //
const entryTime = ref<any>(new Date());
const visible = ref<boolean>(true);
@ -253,34 +242,33 @@ const reportId = ref<string | number>('');
let countVal = <any>'';
onMounted(() => {
assessmentId.value && getAssList();
if (competitionId.value) {
clearInterval(statusTimer);
statusTimer.value = setInterval((_) => {
getCompetitionStatus();
}, 1000);
per.value = assessmentId?.value ? 1 : competitionId?.value ? 2 : 0;
if (assessmentId.value) {
getAssList();
} else {
getList();
if (competitionId?.value) {
clearInterval(statusTimer);
statusTimer.value = setInterval((_) => {
getCompetitionStatus();
}, 1000);
}
}
});
//
const getList = () => {
return new Promise(async (resolve, reject) => {
const { projects } = await getProjectBySystemId({
systemId: systemId.value,
cId: courseId.value,
mallId: mallId.value,
permissions: per.value,
});
projectList.value = projects;
if (!per.value && !projectId.value) projectId.value = projects[0]?.projectId ?? 0; //
getProDetail()
.then(() => {
resolve();
})
.catch((res) => {
reject();
});
});
const getList = async () => {
const data = {
systemId: systemId.value,
cId: cid?.value ?? '',
mallId: mallId?.value,
permissions: per.value,
};
const { projects } = await getProjectBySystemId(data);
projectList.value = projects;
console.log('🚀 ~ file: index.vue:280 ~ getList ~ projectList.value:', projectList.value);
if (!per.value && !projectId.value) projectId.value = projects[0]?.projectId ?? 0; //
getProDetail();
};
//
@ -434,7 +422,7 @@ const submit = () => {
// const data = {
// classId: this.classId ? this.classId : '',
// className: this.className ? this.className : '',
// curriculumId: this.courseId,
// curriculumId: this.cid,
// startTime: this.per ? this.startTime : util.formatDate('yyyy-MM-dd hh:mm:ss', entryTime), //
// endTime: this.per ? this.endTime : submitTime, //
// submitTime, // 3
@ -559,10 +547,7 @@ const startCount = () => {
}
}
.total-score {
padding: 10px;
font-size: 14px;
text-align: center;
border-radius: 6px;
@apply p-[10px] text-sm text-center rounded-[6px] bg-[#e0e0e0];
}
.submit {
width: 106px;
@ -574,32 +559,32 @@ const startCount = () => {
background-color: #202020;
}
}
/deep/.des {
:deep(.des) {
font-size: 16px;
font-family: 'Microsoft YaHei';
img {
max-width: 100%;
}
}
/deep/.el-collapse-item__wrap {
:deep(.el-collapse-item__wrap) {
border-bottom: none;
}
/deep/.el-collapse-item__header {
:deep(.el-collapse-item__header) {
border-bottom: none;
}
/deep/.el-icon-s-ticket:before {
:deep(.el-icon-s-ticket:before) {
padding: 5px;
font-size: 16px;
}
/deep/.el-collapse-item__arrow {
:deep(.el-collapse-item__arrow) {
margin: 0 5px 0 0;
}
/deep/.info-tab.el-tabs--card {
:deep(.info-tab.el-tabs--card) {
.el-tabs__item {
font-size: 16px;
}
.el-tabs__item.is-active {
color: #fff;
@apply text-white bg-[#568df2];
}
.el-tabs__header .el-tabs__nav {
border: none;
@ -617,7 +602,7 @@ const startCount = () => {
overflow: auto;
}
}
/deep/.el-collapse {
:deep(.el-collapse) {
border-bottom: none;
border-top: none;
}
@ -626,7 +611,7 @@ const startCount = () => {
color: #333;
background-color: #fff;
}
.el-aside /deep/[class*=' el-icon-'],
.el-aside :deep([class*=' el-icon-']),
[class^='el-icon-'] {
line-height: 40px;
font-size: 16px;
@ -640,20 +625,7 @@ const startCount = () => {
background-color: #fff;
}
.p-title {
display: flex;
justify-content: center;
height: 40px;
&.system4 {
background-size: 100% 58px;
}
&.system7,
&.system9 {
background-size: 100% 40px;
}
&.system8,
&.system6 {
background-size: 100% 61px;
}
@apply flex justify-center h-[40px] bg-[url('@/assets/images/panel/header.png')] bg-[length:100%_100%] bg-no-repeat;
p {
padding-left: 10px;
line-height: 40px;
@ -664,14 +636,16 @@ const startCount = () => {
color: #fff;
}
}
/deep/.el-card__body {
:deep(.el-card__body) {
padding: 0;
}
/deep/.task-table {
:deep(.task-table) {
font-size: 12px;
thead {
color: #fff;
font-size: 10px;
@apply text-white text-[10px];
}
th.el-table__cell {
@apply bg-[#badfff];
}
th > .cell {
font-weight: 100;
@ -689,12 +663,14 @@ const startCount = () => {
margin: 0 10px;
font-size: 14px;
}
/deep/.select {
:deep(.select) {
@apply flex-1;
.el-select__caret:before {
content: '\e78f';
// content: '\e78f';
padding: 3px;
font-size: 16px;
color: #fff;
background-color: #568df2;
border-radius: 50%;
}
.el-input__icon {
@ -718,33 +694,26 @@ const startCount = () => {
}
}
.panel {
z-index: 1000;
position: relative;
z-index: 200;
position: fixed;
top: 200px;
bottom: 20px;
left: 0;
width: 0;
height: 0;
.toggle-panel {
position: absolute;
top: 60%;
@apply top-[200px];
&.active {
left: 100%;
}
img {
height: 150px;
@apply top-[35%] left-[100%] bg-[url('@/assets/images/panel/left.png')];
}
}
&.active {
position: fixed;
width: 85%;
height: 70%;
.toggle-panel {
top: 38%;
}
}
}
/deep/.el-container {
:deep(.el-container) {
height: 100%;
&.is-vertical {
background-color: #f5f5f5;

@ -1,11 +1,10 @@
<template>
<div class="min-h-full"
:class="isIndex ? 'index' : 'body'">
<app-header v-if="!isIndex" />
<app-sidebar v-if="!hideNav && !isIndex"
<div class="min-h-full bg-[url('@/assets/images/1.png')] bg-[length:100%_100%] bg-no-repeat">
<app-header />
<app-sidebar v-if="!hideNav"
class="sidebar fixed w-sidebar h-full px-5 overflow-hidden transition-width duration-300 z-40" />
<div class="main min-h-[calc(100vh-85px)] transition-margin duration-300 overflow-auto"
:class="{ 'md:ml-sidebar': !hideNav && !isIndex }">
:class="{ 'md:ml-sidebar': !hideNav }">
<app-main />
</div>
</div>
@ -23,10 +22,6 @@ export default defineComponent({
components: { AppSidebar, AppHeader, AppMain },
setup() {
const route = useRoute();
//
const isIndex = computed(() => {
return route.path === '/';
});
//
const hideNav = computed(() => {
return Setting.hideNavPath.includes(route.path);
@ -34,7 +29,6 @@ export default defineComponent({
useResizeHandler();
return {
isIndex,
hideNav,
};
},

@ -14,9 +14,13 @@ export const routes: Array<RouteRecordRaw> = [
{ path: '/403', component: () => import('@/views/403.vue'), meta: { hidden: true } },
{
path: '',
component: Layout,
meta: { hidden: true },
children: [{ path: '', component: () => import('@/views/Home.vue'), meta: { title: '选择关卡' } }],
component: () => import('@/views/Home.vue'),
meta: { title: '选择关卡' },
},
{
path: '/role',
component: () => import('@/views/Role.vue'),
meta: { title: '选择角色' },
},
{
path: '/product',

@ -1,79 +1,100 @@
<template>
<div class="m-[-0.75rem]">
<div class="flex justify-between items-center h-[64px] px-5 bg-white">
<h1>金融产品设计及数字化营销沙盘系统</h1>
<div class="inline-flex items-center">
<img class="mr-3 cursor-pointer"
src="@/assets/images/level/1.png"
alt="" />
<img class="mr-3 cursor-pointer"
src="@/assets/images/level/2.png"
<div class="flex justify-between items-center h-[64px] px-5 bg-white">
<h1>金融产品设计及数字化营销沙盘系统</h1>
<div class="inline-flex items-center">
<img class="mr-3 cursor-pointer"
src="@/assets/images/level/1.png"
alt="" />
<img class="mr-3 cursor-pointer"
src="@/assets/images/level/2.png"
alt="" />
<img class="cursor-pointer"
src="@/assets/images/level/3.png"
alt="" />
</div>
</div>
<div class="relative min-h-[calc(100vh-64px)] pt-5 pl-5 bg-[url('@/assets/images/level/4.png')] bg-[length:100%_100%] bg-no-repeat">
<div class="relative">
<img src="@/assets/images/level/5.png"
alt="" />
<div class="absolute top-5 left-40 flex items-center cursor-pointer"
@click="collected = !collected">
<img v-if="collected"
src="@/assets/images/level/7.png"
alt="" />
<img class="cursor-pointer"
src="@/assets/images/level/3.png"
<img v-else
src="@/assets/images/level/6.png"
alt="" />
<span class="ml-2 text-sm text-[#999]">仅显示已收藏的项目</span>
</div>
</div>
<div class="relative min-h-[calc(100vh-64px)] pt-5 pl-5 bg-[url('@/assets/images/level/4.png')] bg-[length:100%_100%] bg-no-repeat">
<div class="relative">
<img src="@/assets/images/level/5.png"
alt="" />
<div class="absolute top-5 left-40 flex items-center cursor-pointer"
@click="collected = !collected">
<img v-if="collected"
src="@/assets/images/level/7.png"
<div class="relative mt-5">
<div v-for="(item, i) in levels"
:key="i"
:class="['item', { active: curLevel === item.id }]"
@click="selecLevel(item)">
<span class="num">LV.{{ i + 1 }}</span>
<div class="texts">
<h6>第一关</h6>
<p class="des mul-ellipsis2">{{ item.name }}</p>
<img class="icon"
src="@/assets/images/level/star1.png"
alt="" />
<img v-else
src="@/assets/images/level/6.png"
alt="" />
<span class="ml-2 text-sm text-[#999]">仅显示已收藏的项目</span>
</div>
</div>
<div class="relative mt-5">
<div v-for="(item, i) in levels"
:key="i"
class="item">
<span class="num">LV.{{ i + 1 }}</span>
<div class="texts">
<h6>第一关</h6>
<p class="des mul-ellipsis2">{{ item.name }}</p>
<img class="icon"
src="@/assets/images/level/star1.png"
alt="" />
</div>
</div>
</div>
<img class="arrow top-0 left-[50%] translate-x-[-50%]"
src="@/assets/images/level/arrow-up.png"
alt="" />
<img class="arrow right-0 top-[50%] translate-y-[-50%]"
src="@/assets/images/level/arrow-right.png"
alt="" />
<img class="arrow bottom-0 left-[50%] translate-x-[-50%]"
src="@/assets/images/level/arrow-down.png"
alt="" />
<img class="arrow left-0 top-[50%] translate-y-[-50%]"
src="@/assets/images/level/arrow-left.png"
alt="" />
<div class="absolute bottom-2 right-1 w-[262px] h-[74px] bg-[url('@/assets/images/level/submit.png')] bg-[length:100%_100%] bg-no-repeat cursor-pointer hover:bg-[url('@/assets/images/level/submit-hover.png')]"></div>
</div>
<!-- <Panel /> -->
<img class="arrow top-0 left-[50%] translate-x-[-50%]"
src="@/assets/images/level/arrow-up.png"
alt="" />
<img class="arrow right-0 top-[50%] translate-y-[-50%]"
src="@/assets/images/level/arrow-right.png"
alt="" />
<img class="arrow bottom-0 left-[50%] translate-x-[-50%]"
src="@/assets/images/level/arrow-down.png"
alt="" />
<img class="arrow left-0 top-[50%] translate-y-[-50%]"
src="@/assets/images/level/arrow-left.png"
alt="" />
<div class="absolute bottom-2 right-1 w-[262px] h-[74px] bg-[url('@/assets/images/level/submit.png')] bg-[length:100%_100%] bg-no-repeat cursor-pointer hover:bg-[url('@/assets/images/level/submit-hover.png')]"
@click="toRole"></div>
</div>
<Panel />
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { checkPointList } from '@/api/judgment';
import Panel from '@/components/Panel';
import Panel from '@/components/Panel/index.vue';
import { useRouter, useRoute } from 'vue-router';
import { ElMessage } from 'element-plus';
const router = useRouter();
const route = useRoute();
const collected = ref<boolean>(false);
const curLevel = ref<number | string>('');
const levels = ref<Record<string, any>[]>([]);
//
const getLevel = async () => {
const { data } = await checkPointList(1);
levels.value = data;
};
//
const selecLevel = (item: Record<string, any>) => {
curLevel.value = item.id;
};
//
const toRole = () => {
curLevel.value
? router.push({
path: `/role`,
query: {
...route.query,
levelId: curLevel.value,
},
})
: ElMessage.error('请选择关卡!');
};
onMounted(() => {
getLevel();
});
@ -110,6 +131,14 @@ onMounted(() => {
&:hover {
@apply opacity-80;
}
&.active {
@apply bg-[url('@/assets/images/level/10.png')];
h6 {
@apply bg-none;
text-shadow: none;
-webkit-text-fill-color: #fff;
}
}
&:nth-child(2) {
@apply top-[var(--line2)] left-[150px];
}

@ -0,0 +1,171 @@
<template>
<div class="min-h-[100vh] bg-[url('@/assets/images/role/bg.png')] bg-[length:100%_auto] bg-no-repeat"></div>
<div class="fixed top-4 right-[80px]">
<div class="flex items-center h-[60px] px-4 rounded-tl-[20px] rounded-tr-[20px]"
style="background: linear-gradient(180deg, #7ebaff 0%, #0076ff 100%)">
<div class="w-[112px] h-[28px] bg-[url('@/assets/images/role/1.png')] bg-[length:100%_100%] bg-no-repeat"></div>
<ul class="range inline-flex items-center px-3">
<li v-for="item in ranges"
:key="item"
class="w-[48px] py-[2px] text-center text-xs text-white cursor-pointer">{{ item.name }}</li>
</ul>
<ul class="inline-flex items-center px-2">
<li v-for="item in rank"
:key="item"
class="rank relative px-1 text-center text-sm text-white cursor-pointer">{{ item.name }}</li>
</ul>
</div>
<div class="py-[10px] px-5 bg-white">
<div class="table">
<ul class="thead">
<li class="w-[100px]">排名</li>
<li class="w-[160px]">商品名称</li>
<li class="w-[160px]">产品经理</li>
<li class="w-[160px]">金额()</li>
</ul>
<div class="tbody">
<div v-for="(item, i) in ranks"
:key="i"
class="line">
<div class="w-[100px]">{{ i + 1 }}</div>
<div class="w-[160px]">{{ item.name }}</div>
<div class="w-[160px]">{{ item.user }}</div>
<div class="w-[160px]">{{ item.money }}</div>
</div>
</div>
</div>
</div>
</div>
<Panel />
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { checkPointList } from '@/api/judgment';
import Panel from '@/components/Panel/index.vue';
const collected = ref<boolean>(false);
const curLevel = ref<number | string>('');
const levels = ref<Record<string, any>[]>([]);
const ranges = ref<Record<string, any>[]>([
{
id: 1,
name: '今天',
},
{
id: 2,
name: '近1周',
},
{
id: 3,
name: '近1月',
},
]);
const rank = ref<Record<string, any>[]>([
{
id: 1,
name: '收益排行',
},
{
id: 2,
name: '总资产排行',
},
{
id: 3,
name: '交易订单排行',
},
{
id: 4,
name: '查看更多',
},
]);
const ranks = ref<Record<string, any>[]>([
{
id: 1,
name: '沙盘名称',
user: '沙盘名称',
money: '沙盘名称',
},
{
id: 1,
name: '沙盘名称',
user: '沙盘名称',
money: '沙盘名称',
},
{
id: 1,
name: '沙盘名称',
user: '沙盘名称',
money: '沙盘名称',
},
{
id: 1,
name: '沙盘名称',
user: '沙盘名称',
money: '沙盘名称',
},
{
id: 1,
name: '沙盘名称',
user: '沙盘名称',
money: '沙盘名称',
},
]);
//
const getLevel = async () => {
const { data } = await checkPointList(1);
levels.value = data;
};
//
const selecLevel = (item: Record<string, any>) => {
curLevel.value = item.id;
};
onMounted(() => {
getLevel();
});
</script>
<style lang="scss" scoped>
.range {
li {
border: 1px solid #2864ac;
&:first-child {
border-radius: 4px 0px 0px 4px;
border-right: 0;
}
&:last-child {
border-radius: 0px 4px 4px 0px;
border-left: 0;
}
}
.active {
@apply bg-[#2864AC];
}
}
.rank {
font-family: PingFangSC-Light, PingFang SC;
text-shadow: 0px 2px 4px #0e3868;
&.active {
font-family: PingFangSC-Medium, PingFang SC;
&:after {
content: '';
@apply absolute bottom-0 left-[50%] w-5 h-[3px] bg-white rounded translate-x-[-50%];
}
}
}
.thead {
@apply flex items-center h-[32px] text-white text-center text-sm rounded-lg;
background: linear-gradient(180deg, #7ebaff 0%, #0076ff 100%);
}
.tbody {
.line {
@apply flex items-center h-[32px] my-1 text-[#333] text-center text-sm rounded-lg bg-[#FAFAFA];
box-shadow: 0px 2px 0px 0px rgba(0, 0, 0, 0.1);
&:first-child,
&:nth-child(2),
&:nth-child(3) {
@apply bg-[#FFEFDE];
}
}
}
</style>
Loading…
Cancel
Save