master
parent
1ffbd97577
commit
06342737c5
@ -1,56 +0,0 @@
|
||||
import request from "@/utils/request";
|
||||
|
||||
function customParamsSerializer(params) {
|
||||
let result = "";
|
||||
for (let key in params) {
|
||||
if (Object.prototype.hasOwnProperty.call(params, key)) {
|
||||
if (Array.isArray(params[key])) {
|
||||
params[key].forEach((item, index) => {
|
||||
if (item && item.key) {
|
||||
result += `${key}[${index}][key]=${item.key}&${key}[${index}][op]=${item.op}&${key}[${index}][value]=${item.value}&`;
|
||||
} else {
|
||||
result += `${key}[${index}]=${item}&`;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
result += `${key}=${params[key]}&`;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.slice(0, -1);
|
||||
}
|
||||
|
||||
export function index(params, isLoading = false) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/api/admin/course-plan/index",
|
||||
params,
|
||||
paramsSerializer: customParamsSerializer,
|
||||
isLoading,
|
||||
});
|
||||
}
|
||||
|
||||
export function show(params, isLoading = true) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/api/admin/course-plan/show",
|
||||
params,
|
||||
isLoading,
|
||||
});
|
||||
}
|
||||
|
||||
export function save(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/api/admin/course-plan/save",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
export function destroy(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/api/admin/course-plan/destroy",
|
||||
params,
|
||||
});
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
import request from "@/utils/request";
|
||||
|
||||
function customParamsSerializer(params) {
|
||||
let result = "";
|
||||
for (let key in params) {
|
||||
if (Object.prototype.hasOwnProperty.call(params, key)) {
|
||||
if (Array.isArray(params[key])) {
|
||||
params[key].forEach((item, index) => {
|
||||
if (item && item.key) {
|
||||
result += `${key}[${index}][key]=${item.key}&${key}[${index}][op]=${item.op}&${key}[${index}][value]=${item.value}&`;
|
||||
} else {
|
||||
result += `${key}[${index}]=${item}&`;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
result += `${key}=${params[key]}&`;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.slice(0, -1);
|
||||
}
|
||||
|
||||
export function index(params, isLoading = false) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/api/admin/course-plan-location/index",
|
||||
params,
|
||||
paramsSerializer: customParamsSerializer,
|
||||
isLoading,
|
||||
});
|
||||
}
|
||||
|
||||
export function show(params, isLoading = true) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/api/admin/course-plan-location/show",
|
||||
params,
|
||||
isLoading,
|
||||
});
|
||||
}
|
||||
|
||||
export function save(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/api/admin/course-plan-location/save",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
export function destroy(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/api/admin/course-plan-location/destroy",
|
||||
params,
|
||||
});
|
||||
}
|
||||
@ -1,56 +0,0 @@
|
||||
import request from "@/utils/request";
|
||||
|
||||
function customParamsSerializer(params) {
|
||||
let result = "";
|
||||
for (let key in params) {
|
||||
if (Object.prototype.hasOwnProperty.call(params, key)) {
|
||||
if (Array.isArray(params[key])) {
|
||||
params[key].forEach((item, index) => {
|
||||
if (item && item.key) {
|
||||
result += `${key}[${index}][key]=${item.key}&${key}[${index}][op]=${item.op}&${key}[${index}][value]=${item.value}&`;
|
||||
} else {
|
||||
result += `${key}[${index}]=${item}&`;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
result += `${key}=${params[key]}&`;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.slice(0, -1);
|
||||
}
|
||||
|
||||
export function index(params, isLoading = false) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/api/admin/course-plan-system/index",
|
||||
params,
|
||||
paramsSerializer: customParamsSerializer,
|
||||
isLoading,
|
||||
});
|
||||
}
|
||||
|
||||
export function show(params, isLoading = true) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/api/admin/course-plan-system/show",
|
||||
params,
|
||||
isLoading,
|
||||
});
|
||||
}
|
||||
|
||||
export function save(data) {
|
||||
return request({
|
||||
method: "post",
|
||||
url: "/api/admin/course-plan-system/save",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
export function destroy(params) {
|
||||
return request({
|
||||
method: "get",
|
||||
url: "/api/admin/course-plan-system/destroy",
|
||||
params,
|
||||
});
|
||||
}
|
||||
@ -1,161 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div ref="lxHeader">
|
||||
<lx-header icon="md-apps" :text="$route.meta.title" style="margin-bottom: 10px; border: 0; margin-top: 15px;">
|
||||
<div slot="content">
|
||||
<div class="searchwrap">
|
||||
<div>
|
||||
<el-input v-model="select.name" placeholder="请输入地点名称" clearable />
|
||||
</div>
|
||||
<div>
|
||||
<el-button type="primary" size="small" @click="select.page = 1; getList()">查询</el-button>
|
||||
<el-button type="primary" size="small" @click="resetSelect">重置</el-button>
|
||||
</div>
|
||||
<div>
|
||||
<el-button type="primary" size="small" @click="editInfo('add')">新增地点</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</lx-header>
|
||||
</div>
|
||||
|
||||
<xy-table
|
||||
:list="list"
|
||||
:total="total"
|
||||
:table-item="tableItem"
|
||||
@pageIndexChange="pageIndexChange"
|
||||
@pageSizeChange="pageSizeChange"
|
||||
>
|
||||
<template v-slot:status>
|
||||
<el-table-column align="center" label="状态" width="100" header-align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'">{{ scope.row.status === 1 ? '启用' : '禁用' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
<template v-slot:btns>
|
||||
<el-table-column align="center" label="操作" width="180" header-align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="small" @click="editInfo('editor', scope.row.id)">编辑</el-button>
|
||||
<el-popconfirm style="margin: 0 10px;" title="确定删除吗?" @confirm="deleteList(scope.row.id)">
|
||||
<el-button slot="reference" type="danger" size="small">删除</el-button>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</xy-table>
|
||||
|
||||
<add-location ref="addLocation" @refresh="getList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import myMixins from "@/mixin/selectMixin.js";
|
||||
import { listMockLocations as index, destroyMockLocation as destroy } from "./mockService.js";
|
||||
import addLocation from "./components/addLocation.vue";
|
||||
|
||||
export default {
|
||||
mixins: [myMixins],
|
||||
components: {
|
||||
addLocation,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
select: {
|
||||
name: "",
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
},
|
||||
list: [],
|
||||
total: 0,
|
||||
tableItem: [{
|
||||
prop: "name",
|
||||
label: "地点名称",
|
||||
align: "left",
|
||||
width: 180,
|
||||
}, {
|
||||
prop: "address",
|
||||
label: "详细地址",
|
||||
align: "left",
|
||||
}, {
|
||||
prop: "sort",
|
||||
label: "排序",
|
||||
align: "center",
|
||||
width: 100,
|
||||
}, {
|
||||
prop: "status",
|
||||
label: "状态",
|
||||
align: "center",
|
||||
width: 100,
|
||||
}, {
|
||||
prop: "remark",
|
||||
label: "备注",
|
||||
align: "left",
|
||||
}],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
pageIndexChange(page) {
|
||||
this.select.page = page;
|
||||
this.getList();
|
||||
},
|
||||
pageSizeChange(pageSize) {
|
||||
this.select.page_size = pageSize;
|
||||
this.select.page = 1;
|
||||
this.getList();
|
||||
},
|
||||
resetSelect() {
|
||||
this.select.name = "";
|
||||
this.select.page = 1;
|
||||
this.getList();
|
||||
},
|
||||
async getList() {
|
||||
const filter = [];
|
||||
if (this.select.name) {
|
||||
filter.push({
|
||||
key: "name",
|
||||
op: "like",
|
||||
value: this.select.name,
|
||||
});
|
||||
}
|
||||
const res = await index({
|
||||
page: this.select.page,
|
||||
page_size: this.select.page_size,
|
||||
sort_name: "sort",
|
||||
sort_type: "ASC",
|
||||
filter,
|
||||
});
|
||||
this.list = res.data || [];
|
||||
this.total = res.total || 0;
|
||||
},
|
||||
editInfo(type, id) {
|
||||
this.$refs.addLocation.id = id || "";
|
||||
this.$refs.addLocation.type = type;
|
||||
this.$refs.addLocation.isShow = true;
|
||||
},
|
||||
deleteList(id) {
|
||||
destroy({ id }).then(() => {
|
||||
this.$message.success("删除成功");
|
||||
this.getList();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.searchwrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
|
||||
& > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,494 +0,0 @@
|
||||
const STORAGE_KEY = "course-plan-mock-store";
|
||||
|
||||
const getCurrentYear = () => String(new Date().getFullYear());
|
||||
|
||||
const createInitialState = () => {
|
||||
const currentYear = getCurrentYear();
|
||||
return {
|
||||
courseTypes: [
|
||||
{ id: 1, name: "初创班", sort: 1, status: 1 },
|
||||
{ id: 2, name: "高研班", sort: 2, status: 1 },
|
||||
{ id: 3, name: "零单班", sort: 3, status: 1 },
|
||||
{ id: 4, name: "产业加速营", sort: 4, status: 1 },
|
||||
{ id: 5, name: "第二课堂", sort: 5, status: 1 },
|
||||
{ id: 6, name: "人才培训", sort: 6, status: 1 },
|
||||
{ id: 7, name: "科技大讲堂", sort: 7, status: 1 },
|
||||
{ id: 8, name: "万人培训", sort: 8, status: 1 },
|
||||
],
|
||||
planSystems: [
|
||||
{ id: 1, name: "0-1", sort: 1, status: 1, remark: "初创企业培育计划" },
|
||||
{ id: 2, name: "0-10", sort: 2, status: 1, remark: "成长型企业高研计划" },
|
||||
{ id: 3, name: "10-100", sort: 3, status: 1, remark: "规模企业专题计划" },
|
||||
{ id: 4, name: "产业结构协同创新", sort: 4, status: 1, remark: "产业升级计划" },
|
||||
{ id: 5, name: "科技人才服务", sort: 5, status: 1, remark: "科技人才专项" },
|
||||
{ id: 6, name: "育民营企业家万人培训", sort: 6, status: 1, remark: "民营企业家年度培训计划" },
|
||||
],
|
||||
locations: [
|
||||
{ id: 1, name: "苏州", address: "苏州校区", sort: 1, status: 1, remark: "" },
|
||||
{ id: 2, name: "苏州工业园区", address: "苏州工业园区教学点", sort: 2, status: 1, remark: "" },
|
||||
{ id: 3, name: "苏州高新区", address: "苏州高新区教学点", sort: 3, status: 1, remark: "" },
|
||||
{ id: 4, name: "上海", address: "上海教学点", sort: 4, status: 1, remark: "" },
|
||||
{ id: 5, name: "深圳", address: "深圳教学点", sort: 5, status: 1, remark: "" },
|
||||
{ id: 6, name: "南京", address: "南京教学点", sort: 6, status: 1, remark: "" },
|
||||
{ id: 7, name: "杭州", address: "杭州教学点", sort: 7, status: 1, remark: "" },
|
||||
{ id: 8, name: "无锡", address: "无锡教学点", sort: 8, status: 1, remark: "" },
|
||||
{ id: 9, name: "常州", address: "常州教学点", sort: 9, status: 1, remark: "" },
|
||||
{ id: 10, name: "线上", address: "线上直播", sort: 10, status: 1, remark: "" },
|
||||
{ id: 11, name: "浙江", address: "浙江教学点", sort: 11, status: 1, remark: "" },
|
||||
{ id: 12, name: "北京", address: "北京教学点", sort: 12, status: 1, remark: "" },
|
||||
],
|
||||
plans: [
|
||||
{
|
||||
id: 1,
|
||||
year: currentYear,
|
||||
plan_system_id: 1,
|
||||
course_type_id: 1,
|
||||
course_name: "第二期高校科技成果转化班",
|
||||
details: [
|
||||
{ id: 101, name: "第二期", month: 5, location_id: 1, owner_name: "王老师" },
|
||||
{ id: 102, name: "第二期", month: 7, location_id: 1, owner_name: "王老师" },
|
||||
{ id: 103, name: "第二期", month: 9, location_id: 1, owner_name: "王老师" },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
year: currentYear,
|
||||
plan_system_id: 1,
|
||||
course_type_id: 1,
|
||||
course_name: "第二期技术经理人班",
|
||||
details: [
|
||||
{ id: 104, name: "南大班", month: 6, location_id: 1, owner_name: "陈老师" },
|
||||
{ id: 105, name: "南大班", month: 8, location_id: 1, owner_name: "陈老师" },
|
||||
{ id: 106, name: "南大班", month: 10, location_id: 1, owner_name: "陈老师" },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
year: currentYear,
|
||||
plan_system_id: 2,
|
||||
course_type_id: 2,
|
||||
course_name: "第七届北大光华班",
|
||||
details: [
|
||||
{ id: 107, name: "第六模块", month: 3, location_id: 1, owner_name: "周老师" },
|
||||
{ id: 108, name: "第六模块", month: 5, location_id: 1, owner_name: "周老师" },
|
||||
{ id: 109, name: "第七模块", month: 7, location_id: 1, owner_name: "周老师" },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
year: currentYear,
|
||||
plan_system_id: 2,
|
||||
course_type_id: 2,
|
||||
course_name: "第八届苏大班",
|
||||
details: [
|
||||
{ id: 110, name: "第二模块", month: 4, location_id: 1, owner_name: "李老师" },
|
||||
{ id: 111, name: "第三模块", month: 5, location_id: 1, owner_name: "李老师" },
|
||||
{ id: 112, name: "第五模块", month: 6, location_id: 1, owner_name: "李老师" },
|
||||
{ id: 113, name: "六模块", month: 7, location_id: 1, owner_name: "李老师" },
|
||||
{ id: 114, name: "七模块", month: 9, location_id: 4, owner_name: "李老师" },
|
||||
{ id: 115, name: "八模块", month: 11, location_id: 5, owner_name: "李老师" },
|
||||
{ id: 116, name: "结业", month: 12, location_id: 1, owner_name: "李老师" },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
year: currentYear,
|
||||
plan_system_id: 2,
|
||||
course_type_id: 2,
|
||||
course_name: "第九期中欧班",
|
||||
details: [
|
||||
{ id: 117, name: "开学", month: 5, location_id: 1, owner_name: "赵老师" },
|
||||
{ id: 118, name: "第二模块", month: 8, location_id: 4, owner_name: "赵老师" },
|
||||
{ id: 119, name: "第三模块", month: 10, location_id: 1, owner_name: "赵老师" },
|
||||
{ id: 120, name: "第四模块", month: 12, location_id: 1, owner_name: "赵老师" },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
year: currentYear,
|
||||
plan_system_id: 2,
|
||||
course_type_id: 2,
|
||||
course_name: "第十期商研班",
|
||||
details: [
|
||||
{ id: 121, name: "开学", month: 11, location_id: 1, owner_name: "孙老师" },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
year: currentYear,
|
||||
plan_system_id: 3,
|
||||
course_type_id: 3,
|
||||
course_name: "第二期肇单班",
|
||||
details: [
|
||||
{ id: 122, name: "开学", month: 6, location_id: 1, owner_name: "钱老师" },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
year: currentYear,
|
||||
plan_system_id: 4,
|
||||
course_type_id: 4,
|
||||
course_name: "AI+能源OPC加速营",
|
||||
details: [
|
||||
{ id: 123, name: "", month: 4, location_id: 1, owner_name: "吴老师" },
|
||||
{ id: 124, name: "", month: 5, location_id: 1, owner_name: "吴老师" },
|
||||
{ id: 125, name: "", month: 6, location_id: 1, owner_name: "吴老师" },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
year: currentYear,
|
||||
plan_system_id: 4,
|
||||
course_type_id: 4,
|
||||
course_name: "南大OPC加速营",
|
||||
details: [
|
||||
{ id: 126, name: "", month: 8, location_id: 1, owner_name: "郑老师" },
|
||||
{ id: 127, name: "", month: 9, location_id: 1, owner_name: "郑老师" },
|
||||
{ id: 128, name: "", month: 10, location_id: 1, owner_name: "郑老师" },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
year: currentYear,
|
||||
plan_system_id: 4,
|
||||
course_type_id: 5,
|
||||
course_name: "第二课堂创新沙龙",
|
||||
details: [],
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
year: currentYear,
|
||||
plan_system_id: 5,
|
||||
course_type_id: 6,
|
||||
course_name: "宣传部培训",
|
||||
details: [
|
||||
{ id: 129, name: "第一期", month: 6, location_id: 1, owner_name: "冯老师" },
|
||||
{ id: 130, name: "第二期", month: 9, location_id: 1, owner_name: "冯老师" },
|
||||
{ id: 131, name: "第三期", month: 12, location_id: 1, owner_name: "冯老师" },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
year: currentYear,
|
||||
plan_system_id: 5,
|
||||
course_type_id: 7,
|
||||
course_name: "科技大讲堂专题课",
|
||||
details: [],
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
year: currentYear,
|
||||
plan_system_id: 6,
|
||||
course_type_id: 8,
|
||||
course_name: "第一期万人培训",
|
||||
details: [
|
||||
{ id: 132, name: "南京市", month: 4, location_id: 1, owner_name: "蒋老师" },
|
||||
{ id: 133, name: "苏州市", month: 5, location_id: 11, owner_name: "蒋老师" },
|
||||
{ id: 134, name: "无锡市", month: 6, location_id: 1, owner_name: "蒋老师" },
|
||||
{ id: 135, name: "南通市", month: 7, location_id: 1, owner_name: "蒋老师" },
|
||||
{ id: 136, name: "扬州市", month: 8, location_id: 1, owner_name: "蒋老师" },
|
||||
{ id: 137, name: "镇江市", month: 9, location_id: 1, owner_name: "蒋老师" },
|
||||
{ id: 138, name: "盐城市", month: 10, location_id: 1, owner_name: "蒋老师" },
|
||||
{ id: 139, name: "淮安市", month: 11, location_id: 1, owner_name: "蒋老师" },
|
||||
{ id: 140, name: "宿迁市", month: 12, location_id: 1, owner_name: "蒋老师" },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
year: currentYear,
|
||||
plan_system_id: 6,
|
||||
course_type_id: 8,
|
||||
course_name: "第二期万人培训",
|
||||
details: [
|
||||
{ id: 141, name: "常州市", month: 5, location_id: 12, owner_name: "韩老师" },
|
||||
{ id: 142, name: "泰州市", month: 8, location_id: 1, owner_name: "韩老师" },
|
||||
{ id: 143, name: "徐州市", month: 9, location_id: 1, owner_name: "韩老师" },
|
||||
{ id: 144, name: "徐州市", month: 11, location_id: 1, owner_name: "韩老师" },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const clone = (data) => JSON.parse(JSON.stringify(data));
|
||||
|
||||
const getStorage = () => {
|
||||
if (typeof window === "undefined" || !window.localStorage) {
|
||||
return null;
|
||||
}
|
||||
return window.localStorage;
|
||||
};
|
||||
|
||||
const loadState = () => {
|
||||
const storage = getStorage();
|
||||
if (!storage) {
|
||||
return createInitialState();
|
||||
}
|
||||
const cache = storage.getItem(STORAGE_KEY);
|
||||
if (!cache) {
|
||||
const initialState = createInitialState();
|
||||
storage.setItem(STORAGE_KEY, JSON.stringify(initialState));
|
||||
return initialState;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(cache);
|
||||
} catch (error) {
|
||||
const initialState = createInitialState();
|
||||
storage.setItem(STORAGE_KEY, JSON.stringify(initialState));
|
||||
return initialState;
|
||||
}
|
||||
};
|
||||
|
||||
let store = loadState();
|
||||
|
||||
const persist = () => {
|
||||
const storage = getStorage();
|
||||
if (storage) {
|
||||
storage.setItem(STORAGE_KEY, JSON.stringify(store));
|
||||
}
|
||||
};
|
||||
|
||||
const nextId = (list) => list.reduce((max, item) => Math.max(max, Number(item.id) || 0), 0) + 1;
|
||||
|
||||
const nextDetailId = () => {
|
||||
const maxId = store.plans.reduce((max, plan) => {
|
||||
const detailMax = (plan.details || []).reduce((detailCurrentMax, detail) => Math.max(detailCurrentMax, Number(detail.id) || 0), 0);
|
||||
return Math.max(max, detailMax);
|
||||
}, 0);
|
||||
return maxId + 1;
|
||||
};
|
||||
|
||||
const getFilterValue = (filter, key) => {
|
||||
const target = (filter || []).find((item) => item.key === key);
|
||||
return target ? target.value : "";
|
||||
};
|
||||
|
||||
const applyLikeFilter = (list, filter, key) => {
|
||||
const value = getFilterValue(filter, key);
|
||||
if (!value) {
|
||||
return list;
|
||||
}
|
||||
return list.filter((item) => String(item[key] || "").includes(String(value)));
|
||||
};
|
||||
|
||||
const applyEqFilter = (list, filter, key) => {
|
||||
const value = getFilterValue(filter, key);
|
||||
if (value === "" || value === undefined || value === null) {
|
||||
return list;
|
||||
}
|
||||
return list.filter((item) => String(item[key]) === String(value));
|
||||
};
|
||||
|
||||
const sortBySort = (list) => clone(list).sort((a, b) => {
|
||||
const sortCompare = Number(a.sort || 0) - Number(b.sort || 0);
|
||||
if (sortCompare !== 0) {
|
||||
return sortCompare;
|
||||
}
|
||||
return String(a.name || "").localeCompare(String(b.name || ""), "zh-CN");
|
||||
});
|
||||
|
||||
const getPlanSystemMap = () => {
|
||||
return store.planSystems.reduce((map, item) => {
|
||||
map[item.id] = item;
|
||||
return map;
|
||||
}, {});
|
||||
};
|
||||
|
||||
const getLocationMap = () => {
|
||||
return store.locations.reduce((map, item) => {
|
||||
map[item.id] = item;
|
||||
return map;
|
||||
}, {});
|
||||
};
|
||||
|
||||
const getCourseTypeMap = () => {
|
||||
return store.courseTypes.reduce((map, item) => {
|
||||
map[item.id] = item;
|
||||
return map;
|
||||
}, {});
|
||||
};
|
||||
|
||||
const enrichPlan = (plan) => {
|
||||
const planSystemMap = getPlanSystemMap();
|
||||
const locationMap = getLocationMap();
|
||||
const courseTypeMap = getCourseTypeMap();
|
||||
return {
|
||||
...clone(plan),
|
||||
plan_system: clone(planSystemMap[plan.plan_system_id] || {}),
|
||||
course_type: clone(courseTypeMap[plan.course_type_id] || {}),
|
||||
details: (plan.details || []).map((detail) => ({
|
||||
...clone(detail),
|
||||
location: clone(locationMap[detail.location_id] || {}),
|
||||
})),
|
||||
};
|
||||
};
|
||||
|
||||
export function listMockCourseTypes() {
|
||||
return Promise.resolve({
|
||||
data: sortBySort(store.courseTypes.filter((item) => item.status !== 0)),
|
||||
total: store.courseTypes.length,
|
||||
});
|
||||
}
|
||||
|
||||
export function listMockPlanSystems(params = {}) {
|
||||
let list = sortBySort(store.planSystems);
|
||||
list = applyLikeFilter(list, params.filter, "name");
|
||||
list = applyEqFilter(list, params.filter, "status");
|
||||
return Promise.resolve({
|
||||
data: list,
|
||||
total: list.length,
|
||||
});
|
||||
}
|
||||
|
||||
export function showMockPlanSystem({ id }) {
|
||||
const item = store.planSystems.find((planSystem) => String(planSystem.id) === String(id));
|
||||
return Promise.resolve(clone(item || {}));
|
||||
}
|
||||
|
||||
export function saveMockPlanSystem(data) {
|
||||
if (data.id) {
|
||||
const index = store.planSystems.findIndex((item) => String(item.id) === String(data.id));
|
||||
if (index > -1) {
|
||||
store.planSystems.splice(index, 1, {
|
||||
...store.planSystems[index],
|
||||
...clone(data),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
store.planSystems.push({
|
||||
id: nextId(store.planSystems),
|
||||
name: data.name,
|
||||
sort: data.sort || 0,
|
||||
status: data.status === 0 ? 0 : 1,
|
||||
remark: data.remark || "",
|
||||
});
|
||||
}
|
||||
persist();
|
||||
return Promise.resolve({ success: true });
|
||||
}
|
||||
|
||||
export function destroyMockPlanSystem({ id }) {
|
||||
store.planSystems = store.planSystems.filter((item) => String(item.id) !== String(id));
|
||||
store.plans = store.plans.filter((item) => String(item.plan_system_id) !== String(id));
|
||||
persist();
|
||||
return Promise.resolve({ success: true });
|
||||
}
|
||||
|
||||
export function listMockLocations(params = {}) {
|
||||
let list = sortBySort(store.locations);
|
||||
list = applyLikeFilter(list, params.filter, "name");
|
||||
list = applyEqFilter(list, params.filter, "status");
|
||||
return Promise.resolve({
|
||||
data: list,
|
||||
total: list.length,
|
||||
});
|
||||
}
|
||||
|
||||
export function showMockLocation({ id }) {
|
||||
const item = store.locations.find((location) => String(location.id) === String(id));
|
||||
return Promise.resolve(clone(item || {}));
|
||||
}
|
||||
|
||||
export function saveMockLocation(data) {
|
||||
if (data.id) {
|
||||
const index = store.locations.findIndex((item) => String(item.id) === String(data.id));
|
||||
if (index > -1) {
|
||||
store.locations.splice(index, 1, {
|
||||
...store.locations[index],
|
||||
...clone(data),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
store.locations.push({
|
||||
id: nextId(store.locations),
|
||||
name: data.name,
|
||||
address: data.address || "",
|
||||
sort: data.sort || 0,
|
||||
status: data.status === 0 ? 0 : 1,
|
||||
remark: data.remark || "",
|
||||
});
|
||||
}
|
||||
persist();
|
||||
return Promise.resolve({ success: true });
|
||||
}
|
||||
|
||||
export function destroyMockLocation({ id }) {
|
||||
store.locations = store.locations.filter((item) => String(item.id) !== String(id));
|
||||
store.plans = store.plans.map((plan) => ({
|
||||
...plan,
|
||||
details: (plan.details || []).filter((detail) => String(detail.location_id) !== String(id)),
|
||||
}));
|
||||
persist();
|
||||
return Promise.resolve({ success: true });
|
||||
}
|
||||
|
||||
export function listMockPlans({ filter = [] } = {}) {
|
||||
const year = getFilterValue(filter, "year") || getCurrentYear();
|
||||
const planSystemMap = getPlanSystemMap();
|
||||
const courseTypeMap = getCourseTypeMap();
|
||||
const list = store.plans
|
||||
.filter((plan) => String(plan.year) === String(year))
|
||||
.map((plan) => enrichPlan(plan))
|
||||
.sort((a, b) => {
|
||||
const planSort = Number((planSystemMap[a.plan_system_id] || {}).sort || 0) - Number((planSystemMap[b.plan_system_id] || {}).sort || 0);
|
||||
if (planSort !== 0) {
|
||||
return planSort;
|
||||
}
|
||||
const courseSort = Number((courseTypeMap[a.course_type_id] || {}).sort || 0) - Number((courseTypeMap[b.course_type_id] || {}).sort || 0);
|
||||
if (courseSort !== 0) {
|
||||
return courseSort;
|
||||
}
|
||||
return String(a.course_name || "").localeCompare(String(b.course_name || ""), "zh-CN");
|
||||
});
|
||||
|
||||
return Promise.resolve({
|
||||
data: list,
|
||||
total: list.length,
|
||||
});
|
||||
}
|
||||
|
||||
export function showMockPlan({ id }) {
|
||||
const item = store.plans.find((plan) => String(plan.id) === String(id));
|
||||
return Promise.resolve(enrichPlan(item || { details: [] }));
|
||||
}
|
||||
|
||||
export function saveMockPlan(data) {
|
||||
const details = (data.details || []).map((detail) => ({
|
||||
id: detail.id || nextDetailId(),
|
||||
name: detail.name || "",
|
||||
month: Number(detail.month),
|
||||
location_id: detail.location_id,
|
||||
owner_name: detail.owner_name || "",
|
||||
}));
|
||||
|
||||
if (data.id) {
|
||||
const index = store.plans.findIndex((item) => String(item.id) === String(data.id));
|
||||
if (index > -1) {
|
||||
store.plans.splice(index, 1, {
|
||||
...store.plans[index],
|
||||
year: String(data.year),
|
||||
plan_system_id: data.plan_system_id,
|
||||
course_type_id: data.course_type_id,
|
||||
course_name: data.course_name,
|
||||
details,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
store.plans.push({
|
||||
id: nextId(store.plans),
|
||||
year: String(data.year),
|
||||
plan_system_id: data.plan_system_id,
|
||||
course_type_id: data.course_type_id,
|
||||
course_name: data.course_name,
|
||||
details,
|
||||
});
|
||||
}
|
||||
persist();
|
||||
return Promise.resolve({ success: true });
|
||||
}
|
||||
|
||||
export function destroyMockPlan({ id }) {
|
||||
store.plans = store.plans.filter((item) => String(item.id) !== String(id));
|
||||
persist();
|
||||
return Promise.resolve({ success: true });
|
||||
}
|
||||
@ -1,156 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div ref="lxHeader">
|
||||
<lx-header icon="md-apps" :text="$route.meta.title" style="margin-bottom: 10px; border: 0; margin-top: 15px;">
|
||||
<div slot="content">
|
||||
<div class="searchwrap">
|
||||
<div>
|
||||
<el-input v-model="select.name" placeholder="请输入计划体系名称" clearable />
|
||||
</div>
|
||||
<div>
|
||||
<el-button type="primary" size="small" @click="select.page = 1; getList()">查询</el-button>
|
||||
<el-button type="primary" size="small" @click="resetSelect">重置</el-button>
|
||||
</div>
|
||||
<div>
|
||||
<el-button type="primary" size="small" @click="editInfo('add')">新增计划体系</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</lx-header>
|
||||
</div>
|
||||
|
||||
<xy-table
|
||||
:list="list"
|
||||
:total="total"
|
||||
:table-item="tableItem"
|
||||
@pageIndexChange="pageIndexChange"
|
||||
@pageSizeChange="pageSizeChange"
|
||||
>
|
||||
<template v-slot:status>
|
||||
<el-table-column align="center" label="状态" width="100" header-align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'">{{ scope.row.status === 1 ? '启用' : '禁用' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
<template v-slot:btns>
|
||||
<el-table-column align="center" label="操作" width="180" header-align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="small" @click="editInfo('editor', scope.row.id)">编辑</el-button>
|
||||
<el-popconfirm style="margin: 0 10px;" title="确定删除吗?" @confirm="deleteList(scope.row.id)">
|
||||
<el-button slot="reference" type="danger" size="small">删除</el-button>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</xy-table>
|
||||
|
||||
<add-plan-system ref="addPlanSystem" @refresh="getList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import myMixins from "@/mixin/selectMixin.js";
|
||||
import { listMockPlanSystems as index, destroyMockPlanSystem as destroy } from "./mockService.js";
|
||||
import addPlanSystem from "./components/addPlanSystem.vue";
|
||||
|
||||
export default {
|
||||
mixins: [myMixins],
|
||||
components: {
|
||||
addPlanSystem,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
select: {
|
||||
name: "",
|
||||
page: 1,
|
||||
page_size: 10,
|
||||
},
|
||||
list: [],
|
||||
total: 0,
|
||||
tableItem: [{
|
||||
prop: "name",
|
||||
label: "计划体系",
|
||||
align: "left",
|
||||
}, {
|
||||
prop: "sort",
|
||||
label: "排序",
|
||||
align: "center",
|
||||
width: 100,
|
||||
}, {
|
||||
prop: "status",
|
||||
label: "状态",
|
||||
align: "center",
|
||||
width: 100,
|
||||
}, {
|
||||
prop: "remark",
|
||||
label: "备注",
|
||||
align: "left",
|
||||
}],
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
pageIndexChange(page) {
|
||||
this.select.page = page;
|
||||
this.getList();
|
||||
},
|
||||
pageSizeChange(pageSize) {
|
||||
this.select.page_size = pageSize;
|
||||
this.select.page = 1;
|
||||
this.getList();
|
||||
},
|
||||
resetSelect() {
|
||||
this.select.name = "";
|
||||
this.select.page = 1;
|
||||
this.getList();
|
||||
},
|
||||
async getList() {
|
||||
const filter = [];
|
||||
if (this.select.name) {
|
||||
filter.push({
|
||||
key: "name",
|
||||
op: "like",
|
||||
value: this.select.name,
|
||||
});
|
||||
}
|
||||
const res = await index({
|
||||
page: this.select.page,
|
||||
page_size: this.select.page_size,
|
||||
sort_name: "sort",
|
||||
sort_type: "ASC",
|
||||
filter,
|
||||
});
|
||||
this.list = res.data || [];
|
||||
this.total = res.total || 0;
|
||||
},
|
||||
editInfo(type, id) {
|
||||
this.$refs.addPlanSystem.id = id || "";
|
||||
this.$refs.addPlanSystem.type = type;
|
||||
this.$refs.addPlanSystem.isShow = true;
|
||||
},
|
||||
deleteList(id) {
|
||||
destroy({ id }).then(() => {
|
||||
this.$message.success("删除成功");
|
||||
this.getList();
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.searchwrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
|
||||
& > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<div class="panel">
|
||||
<div class="panel-title">人员负载与交叉分布</div>
|
||||
<div class="table-scroll table-scroll-y limit-rows-8">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>人员</th>
|
||||
<th>总次数</th>
|
||||
<th>峰值月</th>
|
||||
<th>主战场地</th>
|
||||
<th>主战体系</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="item in memberAnalysis" :key="item.name">
|
||||
<td>{{ item.name }}</td>
|
||||
<td>{{ item.total }}</td>
|
||||
<td>{{ item.month }}</td>
|
||||
<td>{{ item.location }}</td>
|
||||
<td>{{ item.tag }}</td>
|
||||
</tr>
|
||||
<tr v-if="!memberAnalysis.length">
|
||||
<td colspan="5" class="empty-cell">暂无数据</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ScheduleMemberOverview',
|
||||
props: {
|
||||
memberAnalysis: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<div class="panel">
|
||||
<div class="panel-title">人员月度开班次数</div>
|
||||
<div class="table-scroll table-scroll-y limit-rows-8">
|
||||
<table class="data-table heatmap-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>人员</th>
|
||||
<th v-for="month in monthLabels" :key="month">{{ month }}</th>
|
||||
<th>合计</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="row in monthlyStats" :key="row.name">
|
||||
<td class="name-cell">{{ row.name }}</td>
|
||||
<td
|
||||
v-for="(value, index) in row.months"
|
||||
:key="row.name + index"
|
||||
:class="['heat-cell', heatClass(value)]"
|
||||
>
|
||||
{{ value ? value : '-' }}
|
||||
</td>
|
||||
<td class="total-cell">{{ row.total }}</td>
|
||||
</tr>
|
||||
<tr v-if="!monthlyStats.length">
|
||||
<td :colspan="monthLabels.length + 2" class="empty-cell">暂无数据</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ScheduleMonthlyHeatmap',
|
||||
props: {
|
||||
monthLabels: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
monthlyStats: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
heatClass: {
|
||||
type: Function,
|
||||
default: () => () => 'heat-empty'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div class="panel">
|
||||
<div class="table-scroll">
|
||||
<table class="plan-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>体系</th>
|
||||
<th>课程</th>
|
||||
<th v-for="month in monthLabels" :key="month">{{ month }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="row in planRows" :key="row.rowKey">
|
||||
<td v-if="row.showGroup" :rowspan="row.groupSpan" :class="['group-cell', row.groupClass]">
|
||||
{{ row.group }}
|
||||
</td>
|
||||
<td :class="['course-cell', row.groupClass]">{{ row.course }}</td>
|
||||
<td
|
||||
v-for="month in monthLabels"
|
||||
:key="row.rowKey + month"
|
||||
class="plan-month-cell"
|
||||
@click="onCellClick(row, month, row.plan[month])"
|
||||
>
|
||||
<div v-if="row.plan[month] && row.plan[month].length" class="plan-chip-list">
|
||||
<div v-for="item in row.plan[month]" :key="item.id" class="plan-chip">
|
||||
<div>{{ item.title }}</div>
|
||||
<div>{{ item.ownerLocation }}</div>
|
||||
<div>{{ item.countText }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="!planRows.length">
|
||||
<td :colspan="monthLabels.length + 2" class="empty-cell">暂无数据</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SchedulePlanMatrix',
|
||||
props: {
|
||||
monthLabels: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
planRows: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onCellClick(row, month, items) {
|
||||
this.$emit('cell-click', row, month, items)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<div class="summary-panel">
|
||||
<div class="summary-grid">
|
||||
<div v-for="item in summaryCards" :key="item.label" class="summary-card">
|
||||
<div class="summary-label">{{ item.label }}</div>
|
||||
<div class="summary-value">
|
||||
<span class="summary-number">{{ item.value }}</span>
|
||||
<span v-if="item.unit" class="summary-unit">{{ item.unit }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ScheduleSummaryPanel',
|
||||
props: {
|
||||
summaryCards: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Loading…
Reference in new issue