dev #8
|
|
@ -37,3 +37,13 @@ export function Edit(info: MenuItem) {
|
||||||
export function Del(ids: number[]) {
|
export function Del(ids: number[]) {
|
||||||
return http.request<Res<MenuItem[]>>("post", `Menu/Del`, { data: ids });
|
return http.request<Res<MenuItem[]>>("post", `Menu/Del`, { data: ids });
|
||||||
}
|
}
|
||||||
|
/**获取角色的菜单 */
|
||||||
|
export function RoleMenu(roleId: number) {
|
||||||
|
return http.request<Res<number[]>>("get", `MenuRelation/RoleMenu?roleId=${roleId}`);
|
||||||
|
}
|
||||||
|
/**修改角色菜单 */
|
||||||
|
export function SetMenu(data: { roleId: number; menuId: number[] }) {
|
||||||
|
return http.request<Res<MenuItem[]>>("post", `MenuRelation/SetMenu`, {
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,3 +56,24 @@ export function getSchoolBusinessPeopleListApi(data: object) {
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @description 导入excel
|
||||||
|
* @return {object}
|
||||||
|
*/
|
||||||
|
export function importExcel(file: File) {
|
||||||
|
let formData = new FormData();
|
||||||
|
formData.append("file", file);
|
||||||
|
return http.request<any>(
|
||||||
|
"post",
|
||||||
|
`SchoolBusiness/Import`,
|
||||||
|
{
|
||||||
|
data: formData
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded"
|
||||||
|
},
|
||||||
|
responseType: "blob"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -19,7 +19,7 @@ const {
|
||||||
userName,
|
userName,
|
||||||
userAvatar,
|
userAvatar,
|
||||||
avatarsStyle,
|
avatarsStyle,
|
||||||
toggleSideBar
|
toggleSideBar,
|
||||||
} = useNav();
|
} = useNav();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -45,7 +45,7 @@ const {
|
||||||
<!-- 全屏 -->
|
<!-- 全屏 -->
|
||||||
<LaySidebarFullScreen id="full-screen" />
|
<LaySidebarFullScreen id="full-screen" />
|
||||||
<!-- 消息通知 -->
|
<!-- 消息通知 -->
|
||||||
<LayNotice id="header-notice" />
|
<LayNotice id="header-notice" v-show="false" />
|
||||||
<!-- 退出登录 -->
|
<!-- 退出登录 -->
|
||||||
<el-dropdown trigger="click">
|
<el-dropdown trigger="click">
|
||||||
<span class="el-dropdown-link navbar-bg-hover select-none">
|
<span class="el-dropdown-link navbar-bg-hover select-none">
|
||||||
|
|
@ -55,20 +55,13 @@ const {
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu class="logout">
|
<el-dropdown-menu class="logout">
|
||||||
<el-dropdown-item @click="logout">
|
<el-dropdown-item @click="logout">
|
||||||
<IconifyIconOffline
|
<IconifyIconOffline :icon="LogoutCircleRLine" style="margin: 5px" />
|
||||||
:icon="LogoutCircleRLine"
|
|
||||||
style="margin: 5px"
|
|
||||||
/>
|
|
||||||
退出系统
|
退出系统
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
<span
|
<span class="set-icon navbar-bg-hover" title="打开系统配置" @click="onPanel">
|
||||||
class="set-icon navbar-bg-hover"
|
|
||||||
title="打开系统配置"
|
|
||||||
@click="onPanel"
|
|
||||||
>
|
|
||||||
<IconifyIconOffline :icon="Setting" />
|
<IconifyIconOffline :icon="Setting" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,9 @@ const noticesNum = ref(0);
|
||||||
const notices = ref(noticesData);
|
const notices = ref(noticesData);
|
||||||
const activeKey = ref(noticesData[0]?.key);
|
const activeKey = ref(noticesData[0]?.key);
|
||||||
|
|
||||||
notices.value.map(v => (noticesNum.value += v.list.length));
|
notices.value.map((v) => (noticesNum.value += v.list.length));
|
||||||
|
|
||||||
const getLabel = computed(
|
const getLabel = computed(() => (item) =>
|
||||||
() => item =>
|
|
||||||
item.name + (item.list.length > 0 ? `(${item.list.length})` : "")
|
item.name + (item.list.length > 0 ? `(${item.list.length})` : "")
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -23,7 +22,7 @@ const getLabel = computed(
|
||||||
'dropdown-badge',
|
'dropdown-badge',
|
||||||
'navbar-bg-hover',
|
'navbar-bg-hover',
|
||||||
'select-none',
|
'select-none',
|
||||||
Number(noticesNum) !== 0 && 'mr-[10px]'
|
Number(noticesNum) !== 0 && 'mr-[10px]',
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<el-badge :value="Number(noticesNum) === 0 ? '' : noticesNum" :max="99">
|
<el-badge :value="Number(noticesNum) === 0 ? '' : noticesNum" :max="99">
|
||||||
|
|
@ -40,11 +39,7 @@ const getLabel = computed(
|
||||||
class="dropdown-tabs"
|
class="dropdown-tabs"
|
||||||
:style="{ width: notices.length === 0 ? '200px' : '330px' }"
|
:style="{ width: notices.length === 0 ? '200px' : '330px' }"
|
||||||
>
|
>
|
||||||
<el-empty
|
<el-empty v-if="notices.length === 0" description="暂无消息" :image-size="60" />
|
||||||
v-if="notices.length === 0"
|
|
||||||
description="暂无消息"
|
|
||||||
:image-size="60"
|
|
||||||
/>
|
|
||||||
<span v-else>
|
<span v-else>
|
||||||
<template v-for="item in notices" :key="item.key">
|
<template v-for="item in notices" :key="item.key">
|
||||||
<el-tab-pane :label="getLabel(item)" :name="`${item.key}`">
|
<el-tab-pane :label="getLabel(item)" :name="`${item.key}`">
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,11 @@ import { ConditionalType, TableConfig } from "@/components/hTable/hTable";
|
||||||
import { onMounted, ref, defineOptions } from "vue";
|
import { onMounted, ref, defineOptions } from "vue";
|
||||||
import { fa } from "element-plus/es/locales.mjs";
|
import { fa } from "element-plus/es/locales.mjs";
|
||||||
import { hTableAPI } from "@/api/hTable";
|
import { hTableAPI } from "@/api/hTable";
|
||||||
import {
|
import { ruleAccount, rulePassword, rulePhone, ruleRequired } from "@/utils/rules";
|
||||||
ruleAccount,
|
|
||||||
rulePassword,
|
|
||||||
rulePhone,
|
|
||||||
ruleRequired
|
|
||||||
} from "@/utils/rules";
|
|
||||||
const ControllerName = "Admin";
|
const ControllerName = "Admin";
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: ControllerName
|
name: ControllerName,
|
||||||
});
|
});
|
||||||
|
|
||||||
function searchCallback(data) {
|
function searchCallback(data) {
|
||||||
|
|
@ -40,7 +35,7 @@ const tableData: TableConfig = {
|
||||||
PageSize: 20,
|
PageSize: 20,
|
||||||
OrderBy: "CreateTime", // 排序
|
OrderBy: "CreateTime", // 排序
|
||||||
defaultConditions: [], // 默认查询条件
|
defaultConditions: [], // 默认查询条件
|
||||||
Conditions: []
|
Conditions: [],
|
||||||
},
|
},
|
||||||
operationColumn: true, // 显示操作按钮
|
operationColumn: true, // 显示操作按钮
|
||||||
operationColumnData: [
|
operationColumnData: [
|
||||||
|
|
@ -48,22 +43,22 @@ const tableData: TableConfig = {
|
||||||
// 操作按钮
|
// 操作按钮
|
||||||
topBtn: false, // 是头部按钮
|
topBtn: false, // 是头部按钮
|
||||||
label: "修改",
|
label: "修改",
|
||||||
btnType: "edit" // 按钮类型 add edit del custom
|
btnType: "edit", // 按钮类型 add edit del custom
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// 操作按钮
|
// 操作按钮
|
||||||
topBtn: true, // 是头部按钮
|
topBtn: true, // 是头部按钮
|
||||||
label: "添加",
|
label: "添加",
|
||||||
btnStyle: "success",
|
btnStyle: "success",
|
||||||
btnType: "add" // 按钮类型 add edit del custom
|
btnType: "add", // 按钮类型 add edit del custom
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
topBtn: false, // 头部按钮
|
topBtn: false, // 头部按钮
|
||||||
show: true,
|
show: true,
|
||||||
label: "删除",
|
label: "删除",
|
||||||
btnType: "del", // 按钮类型 add edit del 不设置则 自定义按钮
|
btnType: "del", // 按钮类型 add edit del 不设置则 自定义按钮
|
||||||
btnStyle: "danger" // topBtn: true才生效 success danger
|
btnStyle: "danger", // topBtn: true才生效 success danger
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
column: {
|
column: {
|
||||||
// 行数据
|
// 行数据
|
||||||
|
|
@ -72,7 +67,7 @@ const tableData: TableConfig = {
|
||||||
search: true,
|
search: true,
|
||||||
add: false, // 字段允许添加
|
add: false, // 字段允许添加
|
||||||
edit: false, // 字段允许修改
|
edit: false, // 字段允许修改
|
||||||
width: "150px"
|
width: "150px",
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
label: "名称",
|
label: "名称",
|
||||||
|
|
@ -81,22 +76,22 @@ const tableData: TableConfig = {
|
||||||
search: true,
|
search: true,
|
||||||
searchType: ConditionalType.Like,
|
searchType: ConditionalType.Like,
|
||||||
add: true, // 字段允许添加
|
add: true, // 字段允许添加
|
||||||
edit: true // 字段允许修改
|
edit: true, // 字段允许修改
|
||||||
},
|
},
|
||||||
Phone: {
|
phone: {
|
||||||
label: "手机号",
|
label: "手机号",
|
||||||
rules: rulePhone,
|
rules: rulePhone,
|
||||||
width: "200px",
|
width: "200px",
|
||||||
search: true,
|
search: true,
|
||||||
add: true, // 字段允许添加
|
add: true, // 字段允许添加
|
||||||
edit: true // 字段允许修改
|
edit: true, // 字段允许修改
|
||||||
},
|
},
|
||||||
account: {
|
account: {
|
||||||
label: "账号",
|
label: "账号",
|
||||||
rules: ruleAccount,
|
rules: ruleAccount,
|
||||||
search: true,
|
search: true,
|
||||||
add: true, // 字段允许添加
|
add: true, // 字段允许添加
|
||||||
edit: false // 字段允许修改
|
edit: false, // 字段允许修改
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
label: "密码",
|
label: "密码",
|
||||||
|
|
@ -105,7 +100,7 @@ const tableData: TableConfig = {
|
||||||
rules: rulePassword,
|
rules: rulePassword,
|
||||||
search: false,
|
search: false,
|
||||||
add: true, // 字段允许添加
|
add: true, // 字段允许添加
|
||||||
edit: false // 字段允许修改
|
edit: false, // 字段允许修改
|
||||||
},
|
},
|
||||||
enable: {
|
enable: {
|
||||||
label: "启用",
|
label: "启用",
|
||||||
|
|
@ -114,7 +109,7 @@ const tableData: TableConfig = {
|
||||||
|
|
||||||
add: true, // 字段允许添加
|
add: true, // 字段允许添加
|
||||||
edit: true, // 字段允许修改
|
edit: true, // 字段允许修改
|
||||||
valueE: true // 编辑时的默认值
|
valueE: true, // 编辑时的默认值
|
||||||
},
|
},
|
||||||
roleId: {
|
roleId: {
|
||||||
label: "角色",
|
label: "角色",
|
||||||
|
|
@ -124,15 +119,15 @@ const tableData: TableConfig = {
|
||||||
add: true, // 字段允许添加
|
add: true, // 字段允许添加
|
||||||
edit: false, // 字段允许修改
|
edit: false, // 字段允许修改
|
||||||
setting: {
|
setting: {
|
||||||
datasource: []
|
datasource: [],
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
data: [],
|
data: [],
|
||||||
pageData: {
|
pageData: {
|
||||||
total: 0
|
total: 0,
|
||||||
},
|
},
|
||||||
selectRows: []
|
selectRows: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const showTable = ref(false);
|
const showTable = ref(false);
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ahTable from "@/components/hTable/index.vue";
|
import ahTable from "@/components/hTable/index.vue";
|
||||||
import { ConditionalType, TableConfig } from "@/components/hTable/hTable";
|
import { ConditionalType, TableConfig } from "@/components/hTable/hTable";
|
||||||
import { onMounted, ref,defineOptions } from "vue";
|
import { onMounted, ref, defineOptions } from "vue";
|
||||||
import { fa } from "element-plus/es/locales.mjs";
|
import { fa } from "element-plus/es/locales.mjs";
|
||||||
import { hTableAPI } from "@/api/hTable";
|
import { hTableAPI } from "@/api/hTable";
|
||||||
const ControllerName = "AdminRole";
|
const ControllerName = "AdminRole";
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: ControllerName
|
name: ControllerName,
|
||||||
});
|
});
|
||||||
|
|
||||||
function searchCallback(data) {}
|
function searchCallback(data) {}
|
||||||
|
|
@ -24,7 +24,7 @@ const tableData: TableConfig = {
|
||||||
PageSize: 20,
|
PageSize: 20,
|
||||||
OrderBy: "CreateTime", // 排序
|
OrderBy: "CreateTime", // 排序
|
||||||
defaultConditions: [], // 默认查询条件
|
defaultConditions: [], // 默认查询条件
|
||||||
Conditions: []
|
Conditions: [],
|
||||||
},
|
},
|
||||||
operationColumn: true, // 显示操作按钮
|
operationColumn: true, // 显示操作按钮
|
||||||
operationColumnData: [
|
operationColumnData: [
|
||||||
|
|
@ -34,28 +34,35 @@ const tableData: TableConfig = {
|
||||||
label: "角色授权",
|
label: "角色授权",
|
||||||
perms: "角色授权", //按钮显示需要的权限码
|
perms: "角色授权", //按钮显示需要的权限码
|
||||||
btnType: "custom", // 按钮类型 add edit del 不设置则 自定义按钮
|
btnType: "custom", // 按钮类型 add edit del 不设置则 自定义按钮
|
||||||
btnStyle: "success" // topBtn: true才生效 success danger
|
btnStyle: "success", // topBtn: true才生效 success danger
|
||||||
|
custom: {
|
||||||
|
// 按钮类型 custom 专用
|
||||||
|
title: "分配权限", // 弹出框title
|
||||||
|
src: "menu/index", // 组件路径
|
||||||
|
width: "1200px", // 弹框宽度
|
||||||
|
height: "800px", // 弹框高度
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// 操作按钮
|
// 操作按钮
|
||||||
topBtn: false, // 是头部按钮
|
topBtn: false, // 是头部按钮
|
||||||
label: "修改",
|
label: "修改",
|
||||||
btnType: "edit" // 按钮类型 add edit del custom
|
btnType: "edit", // 按钮类型 add edit del custom
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// 操作按钮
|
// 操作按钮
|
||||||
topBtn: true, // 是头部按钮
|
topBtn: true, // 是头部按钮
|
||||||
label: "添加",
|
label: "添加",
|
||||||
btnStyle: "success",
|
btnStyle: "success",
|
||||||
btnType: "add" // 按钮类型 add edit del custom
|
btnType: "add", // 按钮类型 add edit del custom
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
topBtn: false, // 头部按钮
|
topBtn: false, // 头部按钮
|
||||||
show: true,
|
show: true,
|
||||||
label: "删除",
|
label: "删除",
|
||||||
btnType: "del", // 按钮类型 add edit del 不设置则 自定义按钮
|
btnType: "del", // 按钮类型 add edit del 不设置则 自定义按钮
|
||||||
btnStyle: "danger" // topBtn: true才生效 success danger
|
btnStyle: "danger", // topBtn: true才生效 success danger
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
column: {
|
column: {
|
||||||
// 行数据
|
// 行数据
|
||||||
|
|
@ -64,7 +71,7 @@ const tableData: TableConfig = {
|
||||||
search: true,
|
search: true,
|
||||||
add: false, // 字段允许添加
|
add: false, // 字段允许添加
|
||||||
edit: false, // 字段允许修改
|
edit: false, // 字段允许修改
|
||||||
width: "150px"
|
width: "150px",
|
||||||
},
|
},
|
||||||
name: {
|
name: {
|
||||||
label: "角色名称",
|
label: "角色名称",
|
||||||
|
|
@ -72,7 +79,7 @@ const tableData: TableConfig = {
|
||||||
search: true,
|
search: true,
|
||||||
searchType: ConditionalType.Like,
|
searchType: ConditionalType.Like,
|
||||||
add: true, // 字段允许添加
|
add: true, // 字段允许添加
|
||||||
edit: true // 字段允许修改
|
edit: true, // 字段允许修改
|
||||||
},
|
},
|
||||||
enable: {
|
enable: {
|
||||||
label: "启用",
|
label: "启用",
|
||||||
|
|
@ -80,14 +87,14 @@ const tableData: TableConfig = {
|
||||||
search: false,
|
search: false,
|
||||||
add: true, // 字段允许添加
|
add: true, // 字段允许添加
|
||||||
edit: true, // 字段允许修改
|
edit: true, // 字段允许修改
|
||||||
valueE: true // 编辑时的默认值
|
valueE: true, // 编辑时的默认值
|
||||||
},
|
},
|
||||||
createTime: {
|
createTime: {
|
||||||
label: "创建时间",
|
label: "创建时间",
|
||||||
type: "datetime",
|
type: "datetime",
|
||||||
search: true,
|
search: true,
|
||||||
add: false, // 字段允许添加
|
add: false, // 字段允许添加
|
||||||
edit: false // 字段允许修改
|
edit: false, // 字段允许修改
|
||||||
},
|
},
|
||||||
remark: {
|
remark: {
|
||||||
label: "备注",
|
label: "备注",
|
||||||
|
|
@ -95,14 +102,14 @@ const tableData: TableConfig = {
|
||||||
editRows: 3,
|
editRows: 3,
|
||||||
search: false,
|
search: false,
|
||||||
add: true, // 字段允许添加
|
add: true, // 字段允许添加
|
||||||
edit: true // 字段允许修改
|
edit: true, // 字段允许修改
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
data: [],
|
data: [],
|
||||||
pageData: {
|
pageData: {
|
||||||
total: 0
|
total: 0,
|
||||||
},
|
},
|
||||||
selectRows: []
|
selectRows: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const showTable = ref(false);
|
const showTable = ref(false);
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ const tableData: TableConfig = {
|
||||||
btnStyle: "primary",
|
btnStyle: "primary",
|
||||||
custom: {
|
custom: {
|
||||||
title: "考试学生班级详情", // 弹出框title
|
title: "考试学生班级详情", // 弹出框title
|
||||||
src: "exam/userDetails", // 组件路径
|
src: "exam/classExamRecord", // 组件路径
|
||||||
width: "1600px", // 弹框宽度
|
width: "1600px", // 弹框宽度
|
||||||
height: "800px", // 弹框高度
|
height: "800px", // 弹框高度
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import ahTable from "@/components/hTable/index.vue";
|
||||||
|
import { ConditionalType, TableConfig } from "@/components/hTable/hTable";
|
||||||
|
import { onMounted, ref, defineOptions } from "vue";
|
||||||
|
import { fa } from "element-plus/es/locales.mjs";
|
||||||
|
import { hTableAPI } from "@/api/hTable";
|
||||||
|
import { getenum } from "@/api/enum";
|
||||||
|
import { ruleRequired, ruleRequiredNumber } from "@/utils/rules";
|
||||||
|
import { DeleteExamInfo, ImportExamInfo } from "@/api/exam";
|
||||||
|
import { entryExamInfo } from "./examFun";
|
||||||
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
|
import { average } from "@pureadmin/utils";
|
||||||
|
const ControllerName = "ClassExamRecord";
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: ControllerName,
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
data: any;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
function searchCallback(data) {}
|
||||||
|
const table = ref<{ initTable: (config: TableConfig) => void }>();
|
||||||
|
const tableData: TableConfig = {
|
||||||
|
apiUrl: `ExamClassInfo`,
|
||||||
|
selectColumn: false, // 列表选择
|
||||||
|
border: false, // 是否显示表格边框
|
||||||
|
searchCallback: searchCallback,
|
||||||
|
search: {
|
||||||
|
// 查询条件
|
||||||
|
show: true,
|
||||||
|
PageIndex: 0,
|
||||||
|
PageSize: 20,
|
||||||
|
OrderByType: 1, // 排序方式
|
||||||
|
OrderBy: "Id", // 排序
|
||||||
|
defaultConditions: [
|
||||||
|
{
|
||||||
|
FieldName: "ClassId",
|
||||||
|
FieldValue: props.data[0].classId + "",
|
||||||
|
ConditionalType: ConditionalType.Equal,
|
||||||
|
},
|
||||||
|
], // 默认查询条件
|
||||||
|
Conditions: [],
|
||||||
|
},
|
||||||
|
operationColumn: true, // 显示操作按钮
|
||||||
|
operationColumnData: [
|
||||||
|
{
|
||||||
|
topBtn: false, // 头部按钮
|
||||||
|
show: true,
|
||||||
|
label: "学生成绩详情",
|
||||||
|
btnType: "custom",
|
||||||
|
btnStyle: "primary",
|
||||||
|
custom: {
|
||||||
|
title: "考试学生班级详情", // 弹出框title
|
||||||
|
src: "exam/userDetails", // 组件路径
|
||||||
|
width: "1600px", // 弹框宽度
|
||||||
|
height: "880px", // 弹框高度
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
column: {
|
||||||
|
// 行数据
|
||||||
|
examName: {
|
||||||
|
label: "考试名称",
|
||||||
|
search: true,
|
||||||
|
width: "150px",
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
label: "考试类型",
|
||||||
|
search: true,
|
||||||
|
type: "dropdown",
|
||||||
|
setting: {},
|
||||||
|
width: "80px",
|
||||||
|
},
|
||||||
|
testPaperType: {
|
||||||
|
label: "试卷类型",
|
||||||
|
search: true,
|
||||||
|
type: "dropdown",
|
||||||
|
setting: {},
|
||||||
|
width: "80px",
|
||||||
|
},
|
||||||
|
grade: {
|
||||||
|
label: "年级",
|
||||||
|
search: true,
|
||||||
|
type: "dropdown",
|
||||||
|
setting: {},
|
||||||
|
width: "60px",
|
||||||
|
},
|
||||||
|
|
||||||
|
onLineCount: {
|
||||||
|
label: "重本人数",
|
||||||
|
search: false,
|
||||||
|
width: "80px",
|
||||||
|
},
|
||||||
|
onLineRate: {
|
||||||
|
label: "重本率",
|
||||||
|
search: false,
|
||||||
|
custom: (row) => `${Math.round(row.onLineRate * 100)}%`,
|
||||||
|
width: "80px",
|
||||||
|
},
|
||||||
|
onLineRanking: {
|
||||||
|
label: "重本率排名",
|
||||||
|
search: false,
|
||||||
|
width: "100px",
|
||||||
|
},
|
||||||
|
maxScore: {
|
||||||
|
label: "最高分[赋分]",
|
||||||
|
search: false,
|
||||||
|
width: "140px",
|
||||||
|
},
|
||||||
|
minScore: {
|
||||||
|
label: "最低分[赋分]",
|
||||||
|
search: false,
|
||||||
|
width: "140px",
|
||||||
|
},
|
||||||
|
average: {
|
||||||
|
label: "总平均分[赋分]",
|
||||||
|
search: false,
|
||||||
|
custom: (row) => `${Math.round(row.average)}`,
|
||||||
|
width: "140px",
|
||||||
|
},
|
||||||
|
average1: {
|
||||||
|
label: "资源校平均分[赋分]",
|
||||||
|
search: false,
|
||||||
|
width: "160px",
|
||||||
|
},
|
||||||
|
averageRank: {
|
||||||
|
label: "总平均分排名",
|
||||||
|
search: false,
|
||||||
|
width: "110px",
|
||||||
|
},
|
||||||
|
rank: {
|
||||||
|
label: "远端平均/资源校平均",
|
||||||
|
search: false,
|
||||||
|
width: "95px",
|
||||||
|
custom: (row) =>
|
||||||
|
`${row.average1 == 0 ? "--" : Math.round((row.average / row.average1) * 100)}%`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: [],
|
||||||
|
pageData: {
|
||||||
|
total: 0,
|
||||||
|
},
|
||||||
|
selectRows: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const showTable = ref(false);
|
||||||
|
onMounted(async () => {
|
||||||
|
//初始化数据原
|
||||||
|
|
||||||
|
tableData.column.grade.setting.datasource = (await getenum("GradeEnum")).data;
|
||||||
|
|
||||||
|
tableData.column.testPaperType.setting.datasource = (
|
||||||
|
await getenum("TestPaperTypeEnum")
|
||||||
|
).data;
|
||||||
|
tableData.column.type.setting.datasource = (await getenum("ExamTypeEnum")).data;
|
||||||
|
showTable.value = true;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div><ahTable v-if="showTable" ref="table" :tableConfig="tableData" /></div>
|
||||||
|
</template>
|
||||||
|
|
@ -1,32 +1,34 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div style="padding-bottom: 5px">
|
<div style="padding-bottom: 5px">
|
||||||
<el-button type="success" @click="() => showDialog(null)">
|
<el-button type="success" v-show="!isAuthorized" @click="() => showDialog(null)">
|
||||||
新增根菜单
|
新增根菜单
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary"> 分配权限 </el-button>
|
<el-button type="primary" v-show="isAuthorized" @click="callBack">
|
||||||
|
分配权限
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-tree
|
<el-tree
|
||||||
:data="treeData"
|
:data="treeData"
|
||||||
:props="treeProps"
|
:props="treeProps"
|
||||||
|
:default-checked-keys="defaultCheckedKeys"
|
||||||
node-key="id"
|
node-key="id"
|
||||||
:default-expand-all="true"
|
:default-expand-all="true"
|
||||||
:highlight-current="true"
|
:highlight-current="true"
|
||||||
:expand-on-click-node="false"
|
:expand-on-click-node="false"
|
||||||
show-checkbox
|
show-checkbox
|
||||||
class="menu-tree"
|
ref="treeRef"
|
||||||
|
:class="isAuthorized ? `menu-tree menu-tree1` : `menu-tree`"
|
||||||
>
|
>
|
||||||
<template #default="{ node, data }">
|
<template #default="{ node, data }">
|
||||||
<div v-if="!data.isButton" class="menu-node">
|
<div v-if="!data.isButton" class="menu-node">
|
||||||
<div class="menu-node">
|
<div class="menu-node">
|
||||||
<i v-if="data.icon" :class="data.icon" class="menu-icon"></i>
|
<i v-if="data.icon" :class="data.icon" class="menu-icon"></i>
|
||||||
<span class="menu-title">{{ data.title }}</span>
|
<span class="menu-title">{{ data.title }}</span>
|
||||||
<span class="menu-path-Rank" v-if="data.rank"
|
<span class="menu-path-Rank" v-if="data.rank">排序[{{ data.rank }}]</span>
|
||||||
>排序[{{ data.rank }}]</span
|
|
||||||
>
|
|
||||||
<span class="menu-path" v-if="data.path">{{ data.path }}</span>
|
<span class="menu-path" v-if="data.path">{{ data.path }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: flex; gap: 6px">
|
<div style="display: flex; gap: 6px" v-show="!isAuthorized">
|
||||||
<el-button
|
<el-button
|
||||||
type="success"
|
type="success"
|
||||||
link
|
link
|
||||||
|
|
@ -50,7 +52,7 @@
|
||||||
{{ data.title }}
|
{{ data.title }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: flex; gap: 6px">
|
<div style="display: flex; gap: 6px" v-show="!isAuthorized">
|
||||||
<el-button type="primary" link @click="() => showDialog(data)">
|
<el-button type="primary" link @click="() => showDialog(data)">
|
||||||
编辑
|
编辑
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
@ -78,19 +80,27 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { MenuAll, MenuItem, Del } from "@/api/menu";
|
import { MenuAll, MenuItem, Del, RoleMenu, SetMenu } from "@/api/menu";
|
||||||
import { ElMessage, ElMessageBox } from "element-plus";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
|
|
||||||
import MenuEdit from "./edit.vue";
|
import MenuEdit from "./edit.vue";
|
||||||
import { ref, computed, onMounted } from "vue";
|
import { ref, computed, onMounted } from "vue";
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: "Menu"
|
name: "Menu",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
data: any;
|
||||||
|
}>();
|
||||||
|
const isAuthorized = props.data != null && props.data.length > 0;
|
||||||
|
const treeRef = ref();
|
||||||
|
|
||||||
|
// 默认选中的节点ID数组
|
||||||
|
const defaultCheckedKeys = ref([0]);
|
||||||
/** 显示弹窗 */
|
/** 显示弹窗 */
|
||||||
const dialogData = ref({
|
const dialogData = ref({
|
||||||
visible: false,
|
visible: false,
|
||||||
info: null
|
info: null,
|
||||||
});
|
});
|
||||||
function showDialog(info: MenuItem) {
|
function showDialog(info: MenuItem) {
|
||||||
dialogData.value.visible = true;
|
dialogData.value.visible = true;
|
||||||
|
|
@ -110,13 +120,36 @@ const handleClose = (done: () => void) => {
|
||||||
// // catch error
|
// // catch error
|
||||||
// });
|
// });
|
||||||
};
|
};
|
||||||
|
async function callBack() {
|
||||||
|
// 获取所有完全选中的节点
|
||||||
|
const checkedNodes = treeRef.value.getCheckedNodes();
|
||||||
|
// 获取所有半选中的节点(如果需要)
|
||||||
|
const halfCheckedNodes = treeRef.value.getHalfCheckedNodes();
|
||||||
|
//提交
|
||||||
|
SetMenu({
|
||||||
|
roleId: props.data[0].id,
|
||||||
|
menuId: checkedNodes
|
||||||
|
.map((node: MenuItem) => node.id)
|
||||||
|
.concat(halfCheckedNodes.map((node: MenuItem) => node.id)),
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
ElMessage.success("分配权限成功");
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.message);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
ElMessage.error("分配权限失败");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function delMenu(menuId: number) {
|
async function delMenu(menuId: number) {
|
||||||
try {
|
try {
|
||||||
await ElMessageBox.confirm("确定要删除此菜单?", "提示", {
|
await ElMessageBox.confirm("确定要删除此菜单?", "提示", {
|
||||||
confirmButtonText: "确定",
|
confirmButtonText: "确定",
|
||||||
cancelButtonText: "取消",
|
cancelButtonText: "取消",
|
||||||
type: "warning"
|
type: "warning",
|
||||||
});
|
});
|
||||||
const res = await Del([menuId]);
|
const res = await Del([menuId]);
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
|
|
@ -134,12 +167,12 @@ const convertToTree = (menus: MenuItem[]): MenuItem[] => {
|
||||||
const tree: MenuItem[] = [];
|
const tree: MenuItem[] = [];
|
||||||
|
|
||||||
// 创建映射并初始化children
|
// 创建映射并初始化children
|
||||||
menus.forEach(menu => {
|
menus.forEach((menu) => {
|
||||||
menuMap.set(menu.id, { ...menu, children: [] });
|
menuMap.set(menu.id, { ...menu, children: [] });
|
||||||
});
|
});
|
||||||
|
|
||||||
// 构建树形结构
|
// 构建树形结构
|
||||||
menuMap.forEach(menu => {
|
menuMap.forEach((menu) => {
|
||||||
if (menu.parentId === 0) {
|
if (menu.parentId === 0) {
|
||||||
tree.push(menu);
|
tree.push(menu);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -153,7 +186,7 @@ const convertToTree = (menus: MenuItem[]): MenuItem[] => {
|
||||||
// 对同级菜单排序
|
// 对同级菜单排序
|
||||||
const sortChildren = (nodes: MenuItem[]) => {
|
const sortChildren = (nodes: MenuItem[]) => {
|
||||||
nodes.sort((a, b) => a.rank - b.rank);
|
nodes.sort((a, b) => a.rank - b.rank);
|
||||||
nodes.forEach(node => {
|
nodes.forEach((node) => {
|
||||||
if (node.children && node.children.length > 0) {
|
if (node.children && node.children.length > 0) {
|
||||||
sortChildren(node.children);
|
sortChildren(node.children);
|
||||||
}
|
}
|
||||||
|
|
@ -170,7 +203,7 @@ const treeData = ref<MenuItem[]>([]);
|
||||||
// 树组件配置
|
// 树组件配置
|
||||||
const treeProps = {
|
const treeProps = {
|
||||||
label: "title",
|
label: "title",
|
||||||
children: "children"
|
children: "children",
|
||||||
};
|
};
|
||||||
async function fetchInitData() {
|
async function fetchInitData() {
|
||||||
const flatData = await MenuAll();
|
const flatData = await MenuAll();
|
||||||
|
|
@ -179,6 +212,7 @@ async function fetchInitData() {
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(flatData.message);
|
ElMessage.error(flatData.message);
|
||||||
}
|
}
|
||||||
|
if (isAuthorized) defaultCheckedKeys.value = (await RoleMenu(props.data[0].id)).data;
|
||||||
}
|
}
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await fetchInitData();
|
await fetchInitData();
|
||||||
|
|
@ -190,6 +224,11 @@ onMounted(async () => {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
max-height: calc(88vh - 48px - 42px);
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.menu-tree1 {
|
||||||
|
max-height: calc(88vh - 120px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-node {
|
.menu-node {
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,7 @@
|
||||||
</el-form-item> -->
|
</el-form-item> -->
|
||||||
|
|
||||||
<el-form-item v-show="search.userType === 1" style="width: 100px">
|
<el-form-item v-show="search.userType === 1" style="width: 100px">
|
||||||
<el-select
|
<el-select v-model="search.level" placeholder="学生层次" clearable filterable>
|
||||||
v-model="search.level"
|
|
||||||
placeholder="学生层次"
|
|
||||||
clearable
|
|
||||||
filterable
|
|
||||||
>
|
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in userLevelList"
|
v-for="item in userLevelList"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
|
|
@ -78,12 +73,7 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item style="width: 100px">
|
<el-form-item style="width: 100px">
|
||||||
<el-select
|
<el-select v-model="search.classId" placeholder="班级" clearable filterable>
|
||||||
v-model="search.classId"
|
|
||||||
placeholder="班级"
|
|
||||||
clearable
|
|
||||||
filterable
|
|
||||||
>
|
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in classList"
|
v-for="item in classList"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
|
|
@ -95,12 +85,7 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item style="width: 100px">
|
<el-form-item style="width: 100px">
|
||||||
<el-select
|
<el-select v-model="search.subjectId" placeholder="科目" clearable filterable>
|
||||||
v-model="search.subjectId"
|
|
||||||
placeholder="科目"
|
|
||||||
clearable
|
|
||||||
filterable
|
|
||||||
>
|
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in subjectList"
|
v-for="item in subjectList"
|
||||||
:key="item.value"
|
:key="item.value"
|
||||||
|
|
@ -117,10 +102,7 @@
|
||||||
>
|
>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-show="selectUser">
|
<el-form-item v-show="selectUser">
|
||||||
<el-button
|
<el-button type="success" @click="selectUserCallBack()" icon="el-icon-check"
|
||||||
type="success"
|
|
||||||
@click="selectUserCallBack()"
|
|
||||||
icon="el-icon-check"
|
|
||||||
>选择用户</el-button
|
>选择用户</el-button
|
||||||
>
|
>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
@ -161,13 +143,9 @@
|
||||||
<el-table-column prop="id" label="用户Id" width="100" />
|
<el-table-column prop="id" label="用户Id" width="100" />
|
||||||
<el-table-column label="用户信息" width="200">
|
<el-table-column label="用户信息" width="200">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag
|
<el-tag :type="getUserTypeTag(scope.row.userType)" style="margin-right: 5px">{{
|
||||||
:type="getUserTypeTag(scope.row.userType)"
|
userTypeList.find((s) => s.value == scope.row.userType)?.text
|
||||||
style="margin-right: 5px"
|
}}</el-tag>
|
||||||
>{{
|
|
||||||
userTypeList.find(s => s.value == scope.row.userType)?.text
|
|
||||||
}}</el-tag
|
|
||||||
>
|
|
||||||
<span>{{ scope.row.realName }} </span>
|
<span>{{ scope.row.realName }} </span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
@ -183,9 +161,7 @@
|
||||||
<div
|
<div
|
||||||
v-for="(position, index) in scope.row.positions"
|
v-for="(position, index) in scope.row.positions"
|
||||||
:key="'Position' + index"
|
:key="'Position' + index"
|
||||||
v-show="
|
v-show="index < 3 || (index >= 3 && showAllPosition.includes(scope.row))"
|
||||||
index < 3 || (index >= 3 && showAllPosition.includes(scope.row))
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<div v-if="position.enable === false">
|
<div v-if="position.enable === false">
|
||||||
<el-tag type="info">{{ position.schoolName || "-" }}</el-tag>
|
<el-tag type="info">{{ position.schoolName || "-" }}</el-tag>
|
||||||
|
|
@ -209,9 +185,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="
|
v-if="scope.row.positions != undefined && scope.row.positions.length > 3"
|
||||||
scope.row.positions != undefined && scope.row.positions.length > 3
|
|
||||||
"
|
|
||||||
@click="showPosition(scope.row)"
|
@click="showPosition(scope.row)"
|
||||||
class="userTagRow"
|
class="userTagRow"
|
||||||
>
|
>
|
||||||
|
|
@ -227,6 +201,7 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<el-pagination
|
<el-pagination
|
||||||
|
style="display: flex; justify-content: center"
|
||||||
@size-change="pageSizeChange"
|
@size-change="pageSizeChange"
|
||||||
@current-change="pageIndexChange"
|
@current-change="pageIndexChange"
|
||||||
:current-page="pagination.total + 1"
|
:current-page="pagination.total + 1"
|
||||||
|
|
@ -264,7 +239,7 @@ import {
|
||||||
getSubjectData,
|
getSubjectData,
|
||||||
getPageUserList,
|
getPageUserList,
|
||||||
UserDetail,
|
UserDetail,
|
||||||
Position
|
Position,
|
||||||
} from "@/api/userCenter";
|
} from "@/api/userCenter";
|
||||||
import { getenum } from "@/api/enum";
|
import { getenum } from "@/api/enum";
|
||||||
import { hTableAPI } from "@/api/hTable";
|
import { hTableAPI } from "@/api/hTable";
|
||||||
|
|
@ -276,7 +251,7 @@ import {
|
||||||
Message,
|
Message,
|
||||||
ArrowDownBold,
|
ArrowDownBold,
|
||||||
Search,
|
Search,
|
||||||
Star
|
Star,
|
||||||
} from "@element-plus/icons-vue";
|
} from "@element-plus/icons-vue";
|
||||||
import { ComboModel } from "@/components/hTable/hTable";
|
import { ComboModel } from "@/components/hTable/hTable";
|
||||||
|
|
||||||
|
|
@ -344,20 +319,20 @@ interface DialogData {
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
selectUser: {
|
selectUser: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false,
|
||||||
},
|
},
|
||||||
selectCallBack: {
|
selectCallBack: {
|
||||||
type: Function,
|
type: Function,
|
||||||
default: () => {}
|
default: () => {},
|
||||||
},
|
},
|
||||||
maxTableHeight: {
|
maxTableHeight: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 580
|
default: 580,
|
||||||
},
|
},
|
||||||
searchData: {
|
searchData: {
|
||||||
type: Object as () => SearchParams,
|
type: Object as () => SearchParams,
|
||||||
default: undefined
|
default: undefined,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const baseUrl = import.meta.env.VITE_APP_BASE_API;
|
const baseUrl = import.meta.env.VITE_APP_BASE_API;
|
||||||
|
|
@ -378,13 +353,13 @@ const search = reactive<SearchParams>({
|
||||||
grade: "",
|
grade: "",
|
||||||
classId: "",
|
classId: "",
|
||||||
subjectId: "",
|
subjectId: "",
|
||||||
positionId: ""
|
positionId: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const userTypeList = ref<ComboModel[]>([
|
const userTypeList = ref<ComboModel[]>([
|
||||||
{ value: 1, text: "学生" },
|
{ value: 1, text: "学生" },
|
||||||
{ value: 2, text: "教师" },
|
{ value: 2, text: "教师" },
|
||||||
{ value: 3, text: "管理员" }
|
{ value: 3, text: "管理员" },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const userLevelList = ref<ComboModel[]>([]);
|
const userLevelList = ref<ComboModel[]>([]);
|
||||||
|
|
@ -395,7 +370,7 @@ const gradeList = ref<ComboModel[]>([
|
||||||
{ value: "初三", text: "初三" },
|
{ value: "初三", text: "初三" },
|
||||||
{ value: "高一", text: "高一" },
|
{ value: "高一", text: "高一" },
|
||||||
{ value: "高二", text: "高二" },
|
{ value: "高二", text: "高二" },
|
||||||
{ value: "高三", text: "高三" }
|
{ value: "高三", text: "高三" },
|
||||||
]);
|
]);
|
||||||
const classList = ref<ComboModel[]>([]);
|
const classList = ref<ComboModel[]>([]);
|
||||||
const subjectList = ref<ComboModel[]>([]);
|
const subjectList = ref<ComboModel[]>([]);
|
||||||
|
|
@ -405,13 +380,13 @@ const table = reactive<TableData>({
|
||||||
data: [],
|
data: [],
|
||||||
selectRows: [],
|
selectRows: [],
|
||||||
sort: "",
|
sort: "",
|
||||||
border: true
|
border: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const pagination = reactive<PaginationData>({
|
const pagination = reactive<PaginationData>({
|
||||||
index: 1,
|
index: 1,
|
||||||
size: 10,
|
size: 10,
|
||||||
total: 0
|
total: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
const dialog = reactive<DialogData>({
|
const dialog = reactive<DialogData>({
|
||||||
|
|
@ -419,32 +394,32 @@ const dialog = reactive<DialogData>({
|
||||||
update: {
|
update: {
|
||||||
title: "",
|
title: "",
|
||||||
visible: false,
|
visible: false,
|
||||||
width: "800px"
|
width: "800px",
|
||||||
},
|
},
|
||||||
editLevel: {
|
editLevel: {
|
||||||
userIds: [],
|
userIds: [],
|
||||||
title: "",
|
title: "",
|
||||||
visible: false,
|
visible: false,
|
||||||
width: "400px"
|
width: "400px",
|
||||||
},
|
},
|
||||||
editSubjectLevel: {
|
editSubjectLevel: {
|
||||||
userIds: [],
|
userIds: [],
|
||||||
title: "",
|
title: "",
|
||||||
visible: false,
|
visible: false,
|
||||||
width: "450px"
|
width: "450px",
|
||||||
},
|
},
|
||||||
bindUser: {
|
bindUser: {
|
||||||
title: "分配权限码",
|
title: "分配权限码",
|
||||||
visible: false,
|
visible: false,
|
||||||
width: "1150px",
|
width: "1150px",
|
||||||
height: ""
|
height: "",
|
||||||
},
|
},
|
||||||
userBindInfo: {
|
userBindInfo: {
|
||||||
title: "用户权限码",
|
title: "用户权限码",
|
||||||
visible: false,
|
visible: false,
|
||||||
width: "1150px",
|
width: "1150px",
|
||||||
height: ""
|
height: "",
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const checkUserBindInfo = () => {
|
const checkUserBindInfo = () => {
|
||||||
|
|
@ -507,7 +482,7 @@ const exportUser = async () => {
|
||||||
SubjectId: search.subjectId || 0,
|
SubjectId: search.subjectId || 0,
|
||||||
PositionId: search.positionId || 0,
|
PositionId: search.positionId || 0,
|
||||||
PageIndex: pagination.index,
|
PageIndex: pagination.index,
|
||||||
PageSize: pagination.size
|
PageSize: pagination.size,
|
||||||
};
|
};
|
||||||
|
|
||||||
// const res = await exportUserApi(data);
|
// const res = await exportUserApi(data);
|
||||||
|
|
@ -559,9 +534,9 @@ const getClass = () => {
|
||||||
const data = {
|
const data = {
|
||||||
schoolId: search.schoolId || 0,
|
schoolId: search.schoolId || 0,
|
||||||
graduationYear: search.graduationYear || 0,
|
graduationYear: search.graduationYear || 0,
|
||||||
grade: search.grade
|
grade: search.grade,
|
||||||
};
|
};
|
||||||
getClassCombo(data).then(res => {
|
getClassCombo(data).then((res) => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
classList.value = res.data;
|
classList.value = res.data;
|
||||||
}
|
}
|
||||||
|
|
@ -581,12 +556,12 @@ const fetchPagedData = (searchUnUse = false) => {
|
||||||
PositionId: search.positionId || 0,
|
PositionId: search.positionId || 0,
|
||||||
PageIndex: pagination.index,
|
PageIndex: pagination.index,
|
||||||
PageSize: pagination.size,
|
PageSize: pagination.size,
|
||||||
UnUsed: searchUnUse
|
UnUsed: searchUnUse,
|
||||||
};
|
};
|
||||||
getPageUserList(data).then(res => {
|
getPageUserList(data).then((res) => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
pagination.total = res.data.total;
|
pagination.total = res.data.total;
|
||||||
res.data.data.forEach(item => {
|
res.data.data.forEach((item) => {
|
||||||
if (item.positions) {
|
if (item.positions) {
|
||||||
item.positions = PositionsSort(item.positions);
|
item.positions = PositionsSort(item.positions);
|
||||||
}
|
}
|
||||||
|
|
@ -666,7 +641,7 @@ const getUserLevelTag = (level: number) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const getUserLevelText = (level: number) => {
|
const getUserLevelText = (level: number) => {
|
||||||
const r = userLevelList.value.filter(w => w.value === level);
|
const r = userLevelList.value.filter((w) => w.value === level);
|
||||||
if (r.length > 0) {
|
if (r.length > 0) {
|
||||||
return r[0].text;
|
return r[0].text;
|
||||||
}
|
}
|
||||||
|
|
@ -728,7 +703,7 @@ const handleEditLevel = () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dialog.editLevel.title = "修改学生层次";
|
dialog.editLevel.title = "修改学生层次";
|
||||||
dialog.editLevel.userIds = table.selectRows.map(w => w.id);
|
dialog.editLevel.userIds = table.selectRows.map((w) => w.id);
|
||||||
dialog.editLevel.visible = true;
|
dialog.editLevel.visible = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -743,7 +718,7 @@ const handleEditSubjectLevel = () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dialog.editSubjectLevel.title = "修改学生科目层次";
|
dialog.editSubjectLevel.title = "修改学生科目层次";
|
||||||
dialog.editSubjectLevel.userIds = table.selectRows.map(w => w.id);
|
dialog.editSubjectLevel.userIds = table.selectRows.map((w) => w.id);
|
||||||
dialog.editSubjectLevel.visible = true;
|
dialog.editSubjectLevel.visible = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -787,7 +762,7 @@ const importData = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const readerBlob = (data: Blob): Promise<any> => {
|
const readerBlob = (data: Blob): Promise<any> => {
|
||||||
return new Promise(resolve => {
|
return new Promise((resolve) => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.readAsText(data, "utf-8");
|
reader.readAsText(data, "utf-8");
|
||||||
reader.onload = function () {
|
reader.onload = function () {
|
||||||
|
|
|
||||||
|
|
@ -205,6 +205,7 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<el-pagination
|
<el-pagination
|
||||||
|
style="display: flex; justify-content: center"
|
||||||
@size-change="pageSizeChange"
|
@size-change="pageSizeChange"
|
||||||
@current-change="pageIndexChange"
|
@current-change="pageIndexChange"
|
||||||
:current-page="pagination.total + 1"
|
:current-page="pagination.total + 1"
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@
|
||||||
}}
|
}}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item label="赴校时间">
|
<el-descriptions-item label="赴校时间">
|
||||||
{{ safeDetail.startTime?.split("T")[0] }}
|
{{ safeDetail.startTimeStr || safeDetail.startTime }}
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
|
|
||||||
|
|
@ -77,7 +77,7 @@
|
||||||
<el-tab-pane
|
<el-tab-pane
|
||||||
v-for="(i, idx) in sortData(safeDetail.feedbackQuestions || [])"
|
v-for="(i, idx) in sortData(safeDetail.feedbackQuestions || [])"
|
||||||
:key="idx"
|
:key="idx"
|
||||||
:label="'问题' + (idx + 1) + (i.solution ? '(已解决)' : '(未解决)')"
|
:label="'问题' + (idx + 1) + (i.solution ? '(✅已解决)' : '(未解决)')"
|
||||||
:name="idx"
|
:name="idx"
|
||||||
>
|
>
|
||||||
<div style="font-size: 12px; margin-bottom: 4px">
|
<div style="font-size: 12px; margin-bottom: 4px">
|
||||||
|
|
@ -87,7 +87,7 @@
|
||||||
{{ i.question }}
|
{{ i.question }}
|
||||||
</div>
|
</div>
|
||||||
<div v-if="i.solution" style="font-size: 12px; margin-top: 10px">
|
<div v-if="i.solution" style="font-size: 12px; margin-top: 10px">
|
||||||
<span> 解决时间:{{ i.endTime.split("T")[0] }} </span>
|
<span> 解决时间:{{ i.endTimeStr || i.endTime }} </span>
|
||||||
<div style="padding: 10px; background-color: #f3f3f3">
|
<div style="padding: 10px; background-color: #f3f3f3">
|
||||||
{{ i.solution }}
|
{{ i.solution }}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -117,15 +117,9 @@
|
||||||
/>
|
/>
|
||||||
<el-divider />
|
<el-divider />
|
||||||
|
|
||||||
<el-descriptions title="解决方案执行跟踪记录" :column="1" border>
|
<el-descriptions title="解决方案执行跟踪记录" :column="1" border> </el-descriptions>
|
||||||
</el-descriptions>
|
|
||||||
<span>需求+解决方案</span>
|
<span>需求+解决方案</span>
|
||||||
<el-input
|
<el-input v-model="solutionText" :rows="4" type="textarea" :disabled="isDetail" />
|
||||||
v-model="solutionText"
|
|
||||||
:rows="4"
|
|
||||||
type="textarea"
|
|
||||||
:disabled="isDetail"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 添加按钮区域 -->
|
<!-- 添加按钮区域 -->
|
||||||
<div style="margin-top: 5px; display: flex; gap: 20px">
|
<div style="margin-top: 5px; display: flex; gap: 20px">
|
||||||
|
|
@ -163,7 +157,7 @@
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div style="font-weight: bold; color: #409eff">
|
<div style="font-weight: bold; color: #409eff">
|
||||||
执行记录{{ index + 1 }}:{{ record.time.split("T")[0] }}
|
执行记录{{ index + 1 }}:{{ record.time }}
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 5px; white-space: pre-wrap">
|
<div style="margin-top: 5px; white-space: pre-wrap">
|
||||||
{{ record.content }}
|
{{ record.content }}
|
||||||
|
|
@ -183,7 +177,7 @@
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<div style="font-weight: bold; color: #a69400">
|
<div style="font-weight: bold; color: #a69400">
|
||||||
完结情况:{{ finishRecord.time.split("T")[0] }}
|
完结情况:{{ finishRecord.time }}
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top: 5px; white-space: pre-wrap">
|
<div style="margin-top: 5px; white-space: pre-wrap">
|
||||||
{{ finishRecord.content }}
|
{{ finishRecord.content }}
|
||||||
|
|
@ -194,12 +188,7 @@
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 操作弹窗 -->
|
<!-- 操作弹窗 -->
|
||||||
<el-dialog
|
<el-dialog v-model="operationDialogVisible" title="操作" width="500px" align-center>
|
||||||
v-model="operationDialogVisible"
|
|
||||||
title="操作"
|
|
||||||
width="500px"
|
|
||||||
align-center
|
|
||||||
>
|
|
||||||
<el-form
|
<el-form
|
||||||
ref="operationFormRef"
|
ref="operationFormRef"
|
||||||
:model="operationForm"
|
:model="operationForm"
|
||||||
|
|
@ -239,10 +228,7 @@ import { ref, reactive, computed, defineProps, defineEmits, watch } from "vue";
|
||||||
import type { FormInstance, FormRules, TabsPaneContext } from "element-plus";
|
import type { FormInstance, FormRules, TabsPaneContext } from "element-plus";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { getSchoolData } from "@/api/userCenter";
|
import { getSchoolData } from "@/api/userCenter";
|
||||||
import {
|
import { getSchoolBusinessPeopleListApi, addOrEditApi } from "@/api/toschoolinfomanage";
|
||||||
getSchoolBusinessPeopleListApi,
|
|
||||||
addOrEditApi
|
|
||||||
} from "@/api/toschoolinfomanage";
|
|
||||||
import { setFips } from "crypto";
|
import { setFips } from "crypto";
|
||||||
|
|
||||||
const activeName = ref<any>(0);
|
const activeName = ref<any>(0);
|
||||||
|
|
@ -267,7 +253,7 @@ const operationDialogVisible = ref(false);
|
||||||
const operationType = ref(""); // 操作类型:markSolved, addRecord, addFinish
|
const operationType = ref(""); // 操作类型:markSolved, addRecord, addFinish
|
||||||
const operationForm = reactive({
|
const operationForm = reactive({
|
||||||
operationTime: "",
|
operationTime: "",
|
||||||
operationContent: ""
|
operationContent: "",
|
||||||
});
|
});
|
||||||
const operationFormRef = ref<FormInstance>();
|
const operationFormRef = ref<FormInstance>();
|
||||||
|
|
||||||
|
|
@ -278,19 +264,19 @@ const finishRecord = ref<{ time: string; content: string } | null>(null);
|
||||||
// 从父级 detailData.solutionRecord 回显本地显示数据
|
// 从父级 detailData.solutionRecord 回显本地显示数据
|
||||||
watch(
|
watch(
|
||||||
() => props.detailData,
|
() => props.detailData,
|
||||||
val => {
|
(val) => {
|
||||||
const sr = (val as any)?.solutionRecord || {};
|
const sr = (val as any)?.solutionRecord || {};
|
||||||
// 执行记录回显
|
// 执行记录回显
|
||||||
const recs = Array.isArray(sr?.record) ? sr.record : [];
|
const recs = Array.isArray(sr?.record) ? sr.record : [];
|
||||||
executionRecords.value = recs.map((r: any) => ({
|
executionRecords.value = recs.map((r: any) => ({
|
||||||
time: r?.executionTime || "",
|
time: r?.executionTimeStr || r?.executionTime || "",
|
||||||
content: r?.executionRecords || ""
|
content: r?.executionRecords || "",
|
||||||
}));
|
}));
|
||||||
// 完结情况回显
|
// 完结情况回显
|
||||||
if (sr?.endRecordTime || sr?.endRecord) {
|
if (sr?.endRecordTime || sr?.endRecord) {
|
||||||
finishRecord.value = {
|
finishRecord.value = {
|
||||||
time: sr?.endRecordTime || "",
|
time: sr?.endRecordTimeStr || "",
|
||||||
content: sr?.endRecord || ""
|
content: sr?.endRecord || "",
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
finishRecord.value = null;
|
finishRecord.value = null;
|
||||||
|
|
@ -318,21 +304,19 @@ const operationContentLabel = computed(() => {
|
||||||
|
|
||||||
// 表单验证规则
|
// 表单验证规则
|
||||||
const operationRules: FormRules = {
|
const operationRules: FormRules = {
|
||||||
operationTime: [
|
operationTime: [{ required: true, message: "请选择操作时间", trigger: "change" }],
|
||||||
{ required: true, message: "请选择操作时间", trigger: "change" }
|
|
||||||
],
|
|
||||||
operationContent: [
|
operationContent: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: `请输入${operationContentLabel.value}`,
|
message: `请输入${operationContentLabel.value}`,
|
||||||
trigger: "blur"
|
trigger: "blur",
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const dialogVisible = computed({
|
const dialogVisible = computed({
|
||||||
get: () => props.visible,
|
get: () => props.visible,
|
||||||
set: v => emit("update:visible", v)
|
set: (v) => emit("update:visible", v),
|
||||||
});
|
});
|
||||||
|
|
||||||
const closeModal = () => {
|
const closeModal = () => {
|
||||||
|
|
@ -344,39 +328,37 @@ const queType = {
|
||||||
10: "双师课堂",
|
10: "双师课堂",
|
||||||
15: "设备",
|
15: "设备",
|
||||||
20: "学生",
|
20: "学生",
|
||||||
999: "其他"
|
999: "其他",
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* 获取未解决问题数量
|
* 获取未解决问题数量
|
||||||
* @param data
|
* @param data
|
||||||
*/
|
*/
|
||||||
const handleUnHandleQust = (data: Array<any>) => {
|
const handleUnHandleQust = (data: Array<any>) => {
|
||||||
return (data || []).filter(i => !i?.solution).length;
|
return (data || []).filter((i) => !i?.solution).length;
|
||||||
};
|
};
|
||||||
const sortData = (data: Array<any>) => {
|
const sortData = (data: Array<any>) => {
|
||||||
const categorizedData = [
|
const categorizedData = [
|
||||||
...data
|
...data
|
||||||
.filter(item => item.questionType === 1)
|
.filter((item) => item.questionType === 1)
|
||||||
.sort((a, b) => a.sort.localeCompare(b.sort)),
|
.sort((a, b) => a.sort.localeCompare(b.sort)),
|
||||||
...data
|
...data
|
||||||
.filter(item => item.questionType === 10)
|
.filter((item) => item.questionType === 10)
|
||||||
.sort((a, b) => a.sort.localeCompare(b.sort)),
|
.sort((a, b) => a.sort.localeCompare(b.sort)),
|
||||||
...data
|
...data
|
||||||
.filter(item => item.questionType === 15)
|
.filter((item) => item.questionType === 15)
|
||||||
.sort((a, b) => a.sort.localeCompare(b.sort)),
|
.sort((a, b) => a.sort.localeCompare(b.sort)),
|
||||||
...data
|
...data
|
||||||
.filter(item => item.questionType === 20)
|
.filter((item) => item.questionType === 20)
|
||||||
.sort((a, b) => a.sort.localeCompare(b.sort)),
|
.sort((a, b) => a.sort.localeCompare(b.sort)),
|
||||||
...data
|
...data
|
||||||
.filter(item => item.questionType === 999)
|
.filter((item) => item.questionType === 999)
|
||||||
.sort((a, b) => a.sort.localeCompare(b.sort))
|
.sort((a, b) => a.sort.localeCompare(b.sort)),
|
||||||
];
|
];
|
||||||
return categorizedData;
|
return categorizedData;
|
||||||
};
|
};
|
||||||
const safeDetail = computed(() => props.detailData || {});
|
const safeDetail = computed(() => props.detailData || {});
|
||||||
const statusText = computed(() =>
|
const statusText = computed(() => (safeDetail.value?.solutionEnd ? "已完结" : "跟进中"));
|
||||||
safeDetail.value?.solutionEnd ? "已完结" : "跟进中"
|
|
||||||
);
|
|
||||||
const statusType = computed(() =>
|
const statusType = computed(() =>
|
||||||
safeDetail.value?.solutionEnd ? "success" : "warning"
|
safeDetail.value?.solutionEnd ? "success" : "warning"
|
||||||
);
|
);
|
||||||
|
|
@ -387,13 +369,13 @@ const solutionText = computed({
|
||||||
safeDetail.value.solutionRecord = {};
|
safeDetail.value.solutionRecord = {};
|
||||||
}
|
}
|
||||||
safeDetail.value.solutionRecord.solution = value;
|
safeDetail.value.solutionRecord.solution = value;
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 未解决问题数量(依赖每个问题项的 solution 字段,确保标记已解决后自动更新)
|
// 未解决问题数量(依赖每个问题项的 solution 字段,确保标记已解决后自动更新)
|
||||||
const unresolvedCount = computed(() => {
|
const unresolvedCount = computed(() => {
|
||||||
const list = (safeDetail.value?.feedbackQuestions as any[]) || [];
|
const list = (safeDetail.value?.feedbackQuestions as any[]) || [];
|
||||||
return list.filter(item => !item?.solution).length;
|
return list.filter((item) => !item?.solution).length;
|
||||||
});
|
});
|
||||||
const markTitle = (data: any) => {
|
const markTitle = (data: any) => {
|
||||||
console.log("标记已解决", data);
|
console.log("标记已解决", data);
|
||||||
|
|
@ -416,7 +398,7 @@ const addFinish = () => {
|
||||||
const sr = (props.detailData as any)?.solutionRecord;
|
const sr = (props.detailData as any)?.solutionRecord;
|
||||||
// 优先从父级已有完结情况预填,其次使用本地 finishRecord
|
// 优先从父级已有完结情况预填,其次使用本地 finishRecord
|
||||||
if (sr && (sr.endRecordTime || sr.endRecord)) {
|
if (sr && (sr.endRecordTime || sr.endRecord)) {
|
||||||
operationForm.operationTime = sr.endRecordTime || "";
|
operationForm.operationTime = sr.endRecordTimeStr || sr.endRecordTime || "";
|
||||||
operationForm.operationContent = sr.endRecord || "";
|
operationForm.operationContent = sr.endRecord || "";
|
||||||
} else if (finishRecord.value) {
|
} else if (finishRecord.value) {
|
||||||
operationForm.operationTime = finishRecord.value.time;
|
operationForm.operationTime = finishRecord.value.time;
|
||||||
|
|
@ -455,27 +437,25 @@ const confirmOperation = async () => {
|
||||||
// 添加执行记录
|
// 添加执行记录
|
||||||
executionRecords.value.push({
|
executionRecords.value.push({
|
||||||
time: operationTime,
|
time: operationTime,
|
||||||
content: operationContent
|
content: operationContent,
|
||||||
});
|
});
|
||||||
// 同步到父数据 solutionRecord.record
|
// 同步到父数据 solutionRecord.record
|
||||||
if (!props.detailData.solutionRecord)
|
if (!props.detailData.solutionRecord) props.detailData.solutionRecord = {} as any;
|
||||||
props.detailData.solutionRecord = {} as any;
|
|
||||||
if (!Array.isArray(props.detailData.solutionRecord.record))
|
if (!Array.isArray(props.detailData.solutionRecord.record))
|
||||||
props.detailData.solutionRecord.record = [];
|
props.detailData.solutionRecord.record = [];
|
||||||
props.detailData.solutionRecord.record.push({
|
props.detailData.solutionRecord.record.push({
|
||||||
executionTime: operationTime,
|
executionTime: operationTime,
|
||||||
executionRecords: operationContent
|
executionRecords: operationContent,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "addFinish":
|
case "addFinish":
|
||||||
// 添加或修改完结情况
|
// 添加或修改完结情况
|
||||||
finishRecord.value = {
|
finishRecord.value = {
|
||||||
time: operationTime,
|
time: operationTime,
|
||||||
content: operationContent
|
content: operationContent,
|
||||||
};
|
};
|
||||||
// 同步到父数据 solutionRecord.endRecordTime / endRecord
|
// 同步到父数据 solutionRecord.endRecordTime / endRecord
|
||||||
if (!props.detailData.solutionRecord)
|
if (!props.detailData.solutionRecord) props.detailData.solutionRecord = {} as any;
|
||||||
props.detailData.solutionRecord = {} as any;
|
|
||||||
props.detailData.solutionRecord.endRecordTime = operationTime;
|
props.detailData.solutionRecord.endRecordTime = operationTime;
|
||||||
props.detailData.solutionRecord.endRecord = operationContent;
|
props.detailData.solutionRecord.endRecord = operationContent;
|
||||||
break;
|
break;
|
||||||
|
|
@ -491,7 +471,7 @@ const confirmOperation = async () => {
|
||||||
console.log("确认操作", {
|
console.log("确认操作", {
|
||||||
type: operationType.value,
|
type: operationType.value,
|
||||||
time: operationTime,
|
time: operationTime,
|
||||||
content: operationContent
|
content: operationContent,
|
||||||
});
|
});
|
||||||
closeOperationDialog();
|
closeOperationDialog();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -514,7 +494,7 @@ function onClickSave() {
|
||||||
console.log("保存", props.detailData);
|
console.log("保存", props.detailData);
|
||||||
let copyParams = JSON.parse(JSON.stringify(props.detailData));
|
let copyParams = JSON.parse(JSON.stringify(props.detailData));
|
||||||
delete copyParams.solutionEnd;
|
delete copyParams.solutionEnd;
|
||||||
addOrEditApi(copyParams).then(res => {
|
addOrEditApi(copyParams).then((res) => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
ElMessage.success("提交成功");
|
ElMessage.success("提交成功");
|
||||||
// 关闭弹窗
|
// 关闭弹窗
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div style="padding: 20px">
|
<div>
|
||||||
<!-- 搜索区域 -->
|
<!-- 搜索区域 -->
|
||||||
<el-form :model="query" inline label-width="80px" class="search-form">
|
<el-form :model="query" inline class="search-form">
|
||||||
<el-form-item label="学校">
|
<el-form-item label="学校">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="query.school"
|
v-model="query.school"
|
||||||
|
|
@ -72,11 +72,14 @@
|
||||||
style="width: 300px"
|
style="width: 300px"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item> </el-form-item>
|
||||||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
|
||||||
<el-button @click="handleReset">重置</el-button>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
|
<!-- 操作按钮区域 -->
|
||||||
|
<div style="margin-bottom: 15px">
|
||||||
|
<el-button type="primary" :icon="Search" @click="handleSearch">查询</el-button>
|
||||||
|
<el-button @click="handleReset">重置</el-button>
|
||||||
|
</div>
|
||||||
<!-- 操作按钮区域 -->
|
<!-- 操作按钮区域 -->
|
||||||
<div style="margin-bottom: 10px">
|
<div style="margin-bottom: 10px">
|
||||||
<el-button type="primary" @click="handleAdd">新建</el-button>
|
<el-button type="primary" @click="handleAdd">新建</el-button>
|
||||||
|
|
@ -85,30 +88,8 @@
|
||||||
<el-button type="info" @click="downLoadTpl">下载模版</el-button>
|
<el-button type="info" @click="downLoadTpl">下载模版</el-button>
|
||||||
</div>
|
</div>
|
||||||
<!-- 表格区域 -->
|
<!-- 表格区域 -->
|
||||||
<el-table :data="listData" border style="width: 100%">
|
<el-table :data="listData" style="width: 100%">
|
||||||
<el-table-column prop="school" label="学校" min-width="140" />
|
<el-table-column label="操作" width="200">
|
||||||
<el-table-column prop="grade" label="年级" min-width="100" />
|
|
||||||
<el-table-column prop="people" label="赴校人员" min-width="120" />
|
|
||||||
<el-table-column prop="times" label="赴校时间" min-width="140" />
|
|
||||||
<el-table-column
|
|
||||||
prop="feedbackTotals"
|
|
||||||
label="反馈问题数量"
|
|
||||||
min-width="140"
|
|
||||||
/>
|
|
||||||
<el-table-column
|
|
||||||
prop="solveTotals"
|
|
||||||
label="解决问题数量"
|
|
||||||
min-width="140"
|
|
||||||
/>
|
|
||||||
<el-table-column label="状态" min-width="110">
|
|
||||||
<template #default="{ row }">
|
|
||||||
<el-tag :type="row.solutionEnd ? 'success' : 'warning'">
|
|
||||||
{{ row.solutionEnd ? "已完结" : "跟进中" }}
|
|
||||||
</el-tag>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<!-- <el-table-column prop="lastTime" label="最后跟进时间" min-width="160" /> -->
|
|
||||||
<el-table-column label="操作" fixed="right" min-width="220">
|
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<!-- <el-button size="small" type="danger" plain @click="onDelete(row)"
|
<!-- <el-button size="small" type="danger" plain @click="onDelete(row)"
|
||||||
>删除</el-button
|
>删除</el-button
|
||||||
|
|
@ -121,27 +102,38 @@
|
||||||
@confirm="onDelete(row)"
|
@confirm="onDelete(row)"
|
||||||
>
|
>
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-button type="danger" size="small">删除</el-button>
|
<el-button type="danger" text size="small">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-popconfirm>
|
</el-popconfirm>
|
||||||
|
|
||||||
<el-button
|
<el-button size="small" type="primary" text @click="onDetailOrFollow(row, true)"
|
||||||
size="small"
|
|
||||||
type="primary"
|
|
||||||
plain
|
|
||||||
@click="onDetailOrFollow(row, true)"
|
|
||||||
>详情</el-button
|
>详情</el-button
|
||||||
>
|
>
|
||||||
<el-button
|
<el-button
|
||||||
v-if="!row.solutionEnd"
|
v-if="row.canOperate && !row.solutionEnd"
|
||||||
size="small"
|
size="small"
|
||||||
type="success"
|
type="success"
|
||||||
plain
|
text
|
||||||
@click="onDetailOrFollow(row, false)"
|
@click="onDetailOrFollow(row, false)"
|
||||||
>跟进</el-button
|
>跟进</el-button
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column prop="school" label="学校" min-width="140" />
|
||||||
|
<el-table-column label="状态" min-width="80">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag :type="row.solutionEnd ? 'success' : 'warning'">
|
||||||
|
{{ row.solutionEnd ? "已完结" : "跟进中" }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="grade" label="年级" min-width="100" />
|
||||||
|
<el-table-column prop="people" label="赴校人员" min-width="120" />
|
||||||
|
<el-table-column prop="times" label="赴校时间" min-width="140" />
|
||||||
|
<el-table-column prop="feedbackTotals" label="反馈问题数量" min-width="140" />
|
||||||
|
<el-table-column prop="solveTotals" label="解决问题数量" min-width="140" />
|
||||||
|
|
||||||
|
<!-- <el-table-column prop="lastTime" label="最后跟进时间" min-width="160" /> -->
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<!-- 分页 -->
|
<!-- 分页 -->
|
||||||
|
|
@ -157,7 +149,7 @@
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<!-- 新建 -->
|
<!-- 新建 -->
|
||||||
<AddModal v-model:visible="isShowAddModal" @handleReset="handleReset" />
|
<AddModal v-model:visible="isShowAddModal" @handleReset="handleReset" />
|
||||||
<!-- 跟进 -->
|
<!-- 跟进 -->
|
||||||
|
|
@ -168,6 +160,7 @@
|
||||||
:isDetail="isDetail"
|
:isDetail="isDetail"
|
||||||
@handleReset="handleReset"
|
@handleReset="handleReset"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<!-- 赴校信息管理菜单 -->
|
<!-- 赴校信息管理菜单 -->
|
||||||
<script setup lang="ts" name="Toschoolinfomanage">
|
<script setup lang="ts" name="Toschoolinfomanage">
|
||||||
|
|
@ -176,13 +169,15 @@ import {
|
||||||
getPageListApi,
|
getPageListApi,
|
||||||
getSchoolBusinessDetailApi,
|
getSchoolBusinessDetailApi,
|
||||||
deleteSchoolBusinessApi,
|
deleteSchoolBusinessApi,
|
||||||
getSchoolBusinessPeopleListApi
|
getSchoolBusinessPeopleListApi,
|
||||||
|
importExcel,
|
||||||
} from "@/api/toschoolinfomanage";
|
} from "@/api/toschoolinfomanage";
|
||||||
import { getSchoolData } from "@/api/userCenter";
|
import { getSchoolData } from "@/api/userCenter";
|
||||||
import { ref, reactive, computed, onMounted } from "vue";
|
import { ref, reactive, computed, onMounted } from "vue";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import AddModal from "./addModal.vue";
|
import AddModal from "./addModal.vue";
|
||||||
|
import { Check, Search } from "@element-plus/icons-vue";
|
||||||
import EditModal from "./editModal.vue";
|
import EditModal from "./editModal.vue";
|
||||||
import { message } from "@/utils/message";
|
import { message } from "@/utils/message";
|
||||||
interface TableItem {
|
interface TableItem {
|
||||||
|
|
@ -190,6 +185,7 @@ interface TableItem {
|
||||||
school: string;
|
school: string;
|
||||||
grade: string;
|
grade: string;
|
||||||
people: string;
|
people: string;
|
||||||
|
canOperate: boolean; // 是否可以跟进
|
||||||
times: string; // YYYY-MM-DD
|
times: string; // YYYY-MM-DD
|
||||||
feedbackTotals: number;
|
feedbackTotals: number;
|
||||||
solveTotals: number;
|
solveTotals: number;
|
||||||
|
|
@ -204,11 +200,11 @@ const isDetail = ref(false);
|
||||||
* 获取学校下拉数据
|
* 获取学校下拉数据
|
||||||
*/
|
*/
|
||||||
const getSchoolDataFn = () => {
|
const getSchoolDataFn = () => {
|
||||||
getSchoolData().then(res => {
|
getSchoolData().then((res) => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
schoolOptions.value = res.data.map((i: any) => ({
|
schoolOptions.value = res.data.map((i: any) => ({
|
||||||
label: i.text,
|
label: i.text,
|
||||||
value: i.value
|
value: i.value,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -219,10 +215,10 @@ const getSchoolDataFn = () => {
|
||||||
const getSchoolBusinessPeopleList = () => {
|
const getSchoolBusinessPeopleList = () => {
|
||||||
getSchoolBusinessPeopleListApi({}).then((res: any) => {
|
getSchoolBusinessPeopleListApi({}).then((res: any) => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
peopleOptions.value = (res.data || []).map(i => {
|
peopleOptions.value = (res.data || []).map((i) => {
|
||||||
return {
|
return {
|
||||||
value: i.text,
|
value: i.text,
|
||||||
text: i.text
|
text: i.text,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -245,7 +241,7 @@ const gradeOptions = [
|
||||||
{ label: "初三", value: "初三" },
|
{ label: "初三", value: "初三" },
|
||||||
{ label: "高一", value: "高一" },
|
{ label: "高一", value: "高一" },
|
||||||
{ label: "高二", value: "高二" },
|
{ label: "高二", value: "高二" },
|
||||||
{ label: "高三", value: "高三" }
|
{ label: "高三", value: "高三" },
|
||||||
];
|
];
|
||||||
/**
|
/**
|
||||||
* 新建赴校信息提交
|
* 新建赴校信息提交
|
||||||
|
|
@ -264,8 +260,8 @@ const addOrEdit = () => {
|
||||||
{
|
{
|
||||||
question: "xb测试反馈问题1(双师课堂)",
|
question: "xb测试反馈问题1(双师课堂)",
|
||||||
questionType: 10,
|
questionType: 10,
|
||||||
sort: "1111111111"
|
sort: "1111111111",
|
||||||
}
|
},
|
||||||
// {
|
// {
|
||||||
// question: "xb测试反馈问题2(设备)",
|
// question: "xb测试反馈问题2(设备)",
|
||||||
// questionType: 15,
|
// questionType: 15,
|
||||||
|
|
@ -280,7 +276,7 @@ const addOrEdit = () => {
|
||||||
isDiscussion: true,
|
isDiscussion: true,
|
||||||
discussion: "开展座谈座谈座谈座谈座谈座谈座谈座谈座谈座谈座谈座谈座谈座谈",
|
discussion: "开展座谈座谈座谈座谈座谈座谈座谈座谈座谈座谈座谈座谈座谈座谈",
|
||||||
isClassMeeting: true,
|
isClassMeeting: true,
|
||||||
classMeeting: "班会情况班会情况班会情况班会情况班会情况班会情况班会情况"
|
classMeeting: "班会情况班会情况班会情况班会情况班会情况班会情况班会情况",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -289,7 +285,7 @@ const query = reactive({
|
||||||
grade: "" as string | undefined,
|
grade: "" as string | undefined,
|
||||||
people: "" as string | undefined,
|
people: "" as string | undefined,
|
||||||
solutionEnd: undefined,
|
solutionEnd: undefined,
|
||||||
times: [] as string[]
|
times: [] as string[],
|
||||||
});
|
});
|
||||||
const page = ref(1);
|
const page = ref(1);
|
||||||
const pageSize = ref(10);
|
const pageSize = ref(10);
|
||||||
|
|
@ -297,12 +293,8 @@ const total = ref(0);
|
||||||
const listData = ref<TableItem[]>([]);
|
const listData = ref<TableItem[]>([]);
|
||||||
|
|
||||||
function mapApiItemToRow(item: any): TableItem {
|
function mapApiItemToRow(item: any): TableItem {
|
||||||
const peopleArr = Array.isArray(item.schoolBusinessUser)
|
const peopleArr = Array.isArray(item.schoolBusinessUser) ? item.schoolBusinessUser : [];
|
||||||
? item.schoolBusinessUser
|
const start = item.startTime ? dayjs(item.startTime).format("YYYY-MM-DD") : "";
|
||||||
: [];
|
|
||||||
const start = item.startTime
|
|
||||||
? dayjs(item.startTime).format("YYYY-MM-DD")
|
|
||||||
: "";
|
|
||||||
let last = start;
|
let last = start;
|
||||||
const rec = item.solutionRecord?.record || [];
|
const rec = item.solutionRecord?.record || [];
|
||||||
if (Array.isArray(rec) && rec.length > 0) {
|
if (Array.isArray(rec) && rec.length > 0) {
|
||||||
|
|
@ -319,10 +311,11 @@ function mapApiItemToRow(item: any): TableItem {
|
||||||
grade: item.grade || "",
|
grade: item.grade || "",
|
||||||
people: peopleArr.join(","),
|
people: peopleArr.join(","),
|
||||||
times: start,
|
times: start,
|
||||||
|
canOperate: item.canOperate || false, // 是否可以跟进
|
||||||
feedbackTotals: Number(item.feedbackCount) || 0,
|
feedbackTotals: Number(item.feedbackCount) || 0,
|
||||||
solveTotals: Number(item.solveFeedbackCount) || 0,
|
solveTotals: Number(item.solveFeedbackCount) || 0,
|
||||||
solutionEnd: item.solutionEnd,
|
solutionEnd: item.solutionEnd,
|
||||||
lastTime: last
|
lastTime: last,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -330,15 +323,14 @@ async function loadList() {
|
||||||
const payload: any = {
|
const payload: any = {
|
||||||
pageIndex: page.value,
|
pageIndex: page.value,
|
||||||
pageSize: pageSize.value,
|
pageSize: pageSize.value,
|
||||||
orderBy: "startTime"
|
orderBy: "startTime",
|
||||||
};
|
};
|
||||||
if (query.school) payload.schoolId = query.school;
|
if (query.school) payload.schoolId = query.school;
|
||||||
if (query.grade) payload.grade = query.grade;
|
if (query.grade) payload.grade = query.grade;
|
||||||
if (query.people) {
|
if (query.people) {
|
||||||
payload.UserName = query.people;
|
payload.UserName = query.people;
|
||||||
}
|
}
|
||||||
if (typeof query.solutionEnd !== "undefined")
|
if (typeof query.solutionEnd !== "undefined") payload.solutionEnd = query.solutionEnd;
|
||||||
payload.solutionEnd = query.solutionEnd;
|
|
||||||
if (Array.isArray(query.times) && query.times.length === 2) {
|
if (Array.isArray(query.times) && query.times.length === 2) {
|
||||||
payload.startTime = query.times[0];
|
payload.startTime = query.times[0];
|
||||||
payload.endTime = query.times[1];
|
payload.endTime = query.times[1];
|
||||||
|
|
@ -396,7 +388,7 @@ function handleSizeChange(s: number) {
|
||||||
|
|
||||||
function onDelete(row: TableItem) {
|
function onDelete(row: TableItem) {
|
||||||
console.log(`删除`, row);
|
console.log(`删除`, row);
|
||||||
deleteSchoolBusinessApi([row.id]).then(res => {
|
deleteSchoolBusinessApi([row.id]).then((res) => {
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
message("删除成功", { type: "success" });
|
message("删除成功", { type: "success" });
|
||||||
loadList();
|
loadList();
|
||||||
|
|
@ -412,7 +404,7 @@ function onDetailOrFollow(row: TableItem, disabled = false) {
|
||||||
isShowEditModal.value = true;
|
isShowEditModal.value = true;
|
||||||
editModalLoading.value = true;
|
editModalLoading.value = true;
|
||||||
getSchoolBusinessDetailApi(row.id)
|
getSchoolBusinessDetailApi(row.id)
|
||||||
.then(res => {
|
.then((res) => {
|
||||||
if (res.code === 200 && res.data) {
|
if (res.code === 200 && res.data) {
|
||||||
detailData.value = res.data;
|
detailData.value = res.data;
|
||||||
}
|
}
|
||||||
|
|
@ -446,23 +438,63 @@ function handleAdd() {
|
||||||
}
|
}
|
||||||
function handleImport() {
|
function handleImport() {
|
||||||
console.log("批量导入");
|
console.log("批量导入");
|
||||||
|
|
||||||
|
let fileE = document.createElement("input");
|
||||||
|
fileE.type = "file";
|
||||||
|
var formData = new window.FormData();
|
||||||
|
fileE.onchange = async function () {
|
||||||
|
formData.append("file", fileE.files[0]);
|
||||||
|
let res = await importExcel(fileE.files[0]);
|
||||||
|
if (res.code != undefined) {
|
||||||
|
if (res.code !== 200) return ElMessage.error(res.message);
|
||||||
|
else return ElMessage.success("所有数据录入成功");
|
||||||
|
} else if (res.type === "application/json") {
|
||||||
|
let json = await res.text();
|
||||||
|
if (json !== undefined && json.Code !== 200) {
|
||||||
|
return ElMessage.error(json.Message);
|
||||||
|
} else {
|
||||||
|
return ElMessage.success("操所有数据录入成功作成功");
|
||||||
|
}
|
||||||
|
} else if (res === undefined || res.size === 0)
|
||||||
|
return ElMessage.success("所有数据录入成功");
|
||||||
|
const url = res && window.URL.createObjectURL(res);
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.href = url;
|
||||||
|
link.setAttribute("download", "未成功导入的考试信息数据" + ".xlsx");
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
ElMessage.success("导入失败,已导出错误数据");
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
fileE.click();
|
||||||
|
} catch (error) {}
|
||||||
}
|
}
|
||||||
function handleExport() {
|
function handleExport() {
|
||||||
console.log("导出");
|
console.log("导出");
|
||||||
}
|
}
|
||||||
function downLoadTpl() {
|
function downLoadTpl() {
|
||||||
console.log("下载模版");
|
console.log("下载模版");
|
||||||
|
const baseUrl = import.meta.env.VITE_API_BASEURL;
|
||||||
|
const excelImportUsersUrl = `${baseUrl}/SchoolBusiness/DwImportTemplate`;
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.href = excelImportUsersUrl;
|
||||||
|
link.setAttribute("download", "导入赴校信息模板" + ".xlsx");
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
ElMessage.success("下载成功!");
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.search-form {
|
.search-form {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pager {
|
.pager {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: center;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue