项目需求、任务以及模块精简
This commit is contained in:
@@ -43,7 +43,7 @@ import java.io.Serial;
|
||||
@Column(name = "contract_status", attrName = "contractStatus", label = "合同状态"),
|
||||
@Column(name = "payment_status", attrName = "paymentStatus", label = "付款状态"),
|
||||
@Column(name = "remark", attrName = "remark", label = "合同备注", isQuery = false),
|
||||
@Column(name = "create_user", attrName = "createUser", label = "创建人员", isUpdate = false, isQuery = false),
|
||||
@Column(name = "create_user", attrName = "createUser", label = "创建人员", isUpdate = false),
|
||||
@Column(name = "update_time", attrName = "updateTime", label = "更新时间", isQuery = false, isUpdateForce = true),
|
||||
}, joinTable = {
|
||||
@JoinTable(type = Type.LEFT_JOIN, entity = MyProjectInfo.class, alias = "b",
|
||||
|
||||
@@ -43,7 +43,7 @@ import java.io.Serial;
|
||||
@Column(name = "actual_end_time", attrName = "actualEndTime", label = "实际结束", isQuery = false, isUpdateForce = true),
|
||||
@Column(name = "work_hours", attrName = "workHours", label = "工时", isQuery = false),
|
||||
@Column(name = "remark", attrName = "remark", label = "备注", queryType = QueryType.LIKE),
|
||||
@Column(name = "create_user", attrName = "createUser", label = "创建人员", isUpdate = false, isQuery = false),
|
||||
@Column(name = "create_user", attrName = "createUser", label = "创建人员", isUpdate = false),
|
||||
@Column(name = "update_time", attrName = "updateTime", label = "更新时间", isUpdate = false, isQuery = false, isUpdateForce = true),
|
||||
}, joinTable = {
|
||||
@JoinTable(type = Type.LEFT_JOIN, entity = MyProjectInfo.class, alias = "b",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.jeesite.modules.biz.web;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -26,6 +27,7 @@ import com.jeesite.modules.biz.service.MyProjectContractService;
|
||||
|
||||
/**
|
||||
* 项目合同 Controller
|
||||
*
|
||||
* @author gaoxq
|
||||
* @version 2026-04-04
|
||||
*/
|
||||
@@ -98,7 +100,7 @@ public class MyProjectContractController extends BaseController {
|
||||
public void exportData(MyProjectContract myProjectContract, HttpServletResponse response) {
|
||||
List<MyProjectContract> list = myProjectContractService.findList(myProjectContract);
|
||||
String fileName = "合同" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
|
||||
try(ExcelExport ee = new ExcelExport("合同", MyProjectContract.class)){
|
||||
try (ExcelExport ee = new ExcelExport("合同", MyProjectContract.class)) {
|
||||
ee.setDataList(list).write(response, fileName);
|
||||
}
|
||||
}
|
||||
@@ -112,7 +114,7 @@ public class MyProjectContractController extends BaseController {
|
||||
MyProjectContract myProjectContract = new MyProjectContract();
|
||||
List<MyProjectContract> list = ListUtils.newArrayList(myProjectContract);
|
||||
String fileName = "合同模板.xlsx";
|
||||
try(ExcelExport ee = new ExcelExport("合同", MyProjectContract.class, Type.IMPORT)){
|
||||
try (ExcelExport ee = new ExcelExport("合同", MyProjectContract.class, Type.IMPORT)) {
|
||||
ee.setDataList(list).write(response, fileName);
|
||||
}
|
||||
}
|
||||
@@ -126,9 +128,9 @@ public class MyProjectContractController extends BaseController {
|
||||
public String importData(MultipartFile file) {
|
||||
try {
|
||||
String message = myProjectContractService.importData(file);
|
||||
return renderResult(Global.TRUE, "posfull:"+message);
|
||||
return renderResult(Global.TRUE, "posfull:" + message);
|
||||
} catch (Exception ex) {
|
||||
return renderResult(Global.FALSE, "posfull:"+ex.getMessage());
|
||||
return renderResult(Global.FALSE, "posfull:" + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,4 +145,9 @@ public class MyProjectContractController extends BaseController {
|
||||
return renderResult(Global.TRUE, text("删除合同成功!"));
|
||||
}
|
||||
|
||||
@RequestMapping(value = "listAll")
|
||||
@ResponseBody
|
||||
public List<MyProjectContract> listAll(MyProjectContract myProjectContract) {
|
||||
return myProjectContractService.findList(myProjectContract);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.jeesite.modules.biz.web;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -26,6 +27,7 @@ import com.jeesite.modules.biz.service.MyProjectTaskService;
|
||||
|
||||
/**
|
||||
* 项目任务 Controller
|
||||
*
|
||||
* @author gaoxq
|
||||
* @version 2026-04-04
|
||||
*/
|
||||
@@ -98,7 +100,7 @@ public class MyProjectTaskController extends BaseController {
|
||||
public void exportData(MyProjectTask myProjectTask, HttpServletResponse response) {
|
||||
List<MyProjectTask> list = myProjectTaskService.findList(myProjectTask);
|
||||
String fileName = "任务" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
|
||||
try(ExcelExport ee = new ExcelExport("任务", MyProjectTask.class)){
|
||||
try (ExcelExport ee = new ExcelExport("任务", MyProjectTask.class)) {
|
||||
ee.setDataList(list).write(response, fileName);
|
||||
}
|
||||
}
|
||||
@@ -112,7 +114,7 @@ public class MyProjectTaskController extends BaseController {
|
||||
MyProjectTask myProjectTask = new MyProjectTask();
|
||||
List<MyProjectTask> list = ListUtils.newArrayList(myProjectTask);
|
||||
String fileName = "任务模板.xlsx";
|
||||
try(ExcelExport ee = new ExcelExport("任务", MyProjectTask.class, Type.IMPORT)){
|
||||
try (ExcelExport ee = new ExcelExport("任务", MyProjectTask.class, Type.IMPORT)) {
|
||||
ee.setDataList(list).write(response, fileName);
|
||||
}
|
||||
}
|
||||
@@ -126,9 +128,9 @@ public class MyProjectTaskController extends BaseController {
|
||||
public String importData(MultipartFile file) {
|
||||
try {
|
||||
String message = myProjectTaskService.importData(file);
|
||||
return renderResult(Global.TRUE, "posfull:"+message);
|
||||
return renderResult(Global.TRUE, "posfull:" + message);
|
||||
} catch (Exception ex) {
|
||||
return renderResult(Global.FALSE, "posfull:"+ex.getMessage());
|
||||
return renderResult(Global.FALSE, "posfull:" + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,4 +145,11 @@ public class MyProjectTaskController extends BaseController {
|
||||
return renderResult(Global.TRUE, text("删除任务成功!"));
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping(value = "listAll")
|
||||
@ResponseBody
|
||||
public List<MyProjectTask> listAll(MyProjectTask myProjectTask) {
|
||||
return myProjectTaskService.findList(myProjectTask);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
@jeesite:registry=https://maven.jeesite.net/repository/npm-package/
|
||||
registry=https://registry.npmmirror.com
|
||||
package-manager-strict=false
|
||||
auto-install-peers = true
|
||||
git-checks=false
|
||||
@@ -35,6 +35,9 @@ export interface MyProjectContract extends BasicModel<MyProjectContract> {
|
||||
export const myProjectContractList = (params?: MyProjectContract | any) =>
|
||||
defHttp.get<MyProjectContract>({ url: adminPath + '/biz/myProjectContract/list', params });
|
||||
|
||||
export const myProjectContractListAll = (params?: MyProjectContract | any) =>
|
||||
defHttp.get<MyProjectContract[]>({ url: adminPath + '/biz/myProjectContract/listAll', params });
|
||||
|
||||
export const myProjectContractListData = (params?: MyProjectContract | any) =>
|
||||
defHttp.post<Page<MyProjectContract>>({ url: adminPath + '/biz/myProjectContract/listData', params });
|
||||
|
||||
|
||||
@@ -33,6 +33,9 @@ export interface MyProjectTask extends BasicModel<MyProjectTask> {
|
||||
export const myProjectTaskList = (params?: MyProjectTask | any) =>
|
||||
defHttp.get<MyProjectTask>({ url: adminPath + '/biz/myProjectTask/list', params });
|
||||
|
||||
export const myProjectTaskListAll = (params?: MyProjectTask | any) =>
|
||||
defHttp.get<MyProjectTask[]>({ url: adminPath + '/biz/myProjectTask/listAll', params });
|
||||
|
||||
export const myProjectTaskListData = (params?: MyProjectTask | any) =>
|
||||
defHttp.post<Page<MyProjectTask>>({ url: adminPath + '/biz/myProjectTask/listData', params });
|
||||
|
||||
|
||||
@@ -27,7 +27,11 @@
|
||||
import { Icon } from '@jeesite/core/components/Icon';
|
||||
import { BasicForm, FormSchema, useForm } from '@jeesite/core/components/Form';
|
||||
import { BasicDrawer, useDrawerInner } from '@jeesite/core/components/Drawer';
|
||||
import { MyProjectRequirement, myProjectRequirementSave, myProjectRequirementForm } from '@jeesite/biz/api/biz/myProjectRequirement';
|
||||
import {
|
||||
MyProjectRequirement,
|
||||
myProjectRequirementSave,
|
||||
myProjectRequirementForm,
|
||||
} from '@jeesite/biz/api/biz/myProjectRequirement';
|
||||
import { formatToDateTime } from '@jeesite/core/utils/dateUtil';
|
||||
import { useUserStore } from '@jeesite/core/store/modules/user';
|
||||
|
||||
@@ -46,6 +50,10 @@
|
||||
value: record.value.isNewRecord ? t('新增需求') : t('编辑需求'),
|
||||
}));
|
||||
|
||||
function getRequirementNo() {
|
||||
return `WS_${Date.now()}`;
|
||||
}
|
||||
|
||||
const inputFormSchemas: FormSchema<MyProjectRequirement>[] = [
|
||||
{
|
||||
label: t('基本信息'),
|
||||
@@ -59,6 +67,7 @@
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
maxlength: 64,
|
||||
disabled: true,
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
@@ -165,6 +174,9 @@
|
||||
await resetFields();
|
||||
const res = await myProjectRequirementForm(data);
|
||||
record.value = (res.myProjectRequirement || {}) as MyProjectRequirement;
|
||||
if (record.value.isNewRecord) {
|
||||
record.value.requirementNo = getRequirementNo();
|
||||
}
|
||||
record.value.__t = new Date().getTime();
|
||||
await setFieldsValue(record.value);
|
||||
setDrawerProps({ loading: false });
|
||||
@@ -179,8 +191,9 @@
|
||||
requirementId: record.value.requirementId || data.requirementId,
|
||||
};
|
||||
|
||||
if(record.value.isNewRecord){
|
||||
if (record.value.isNewRecord) {
|
||||
data.createUser = userinfo.value.loginCode;
|
||||
data.requirementNo = getRequirementNo();
|
||||
}
|
||||
|
||||
data[record.value.isNewRecord ? 'createTime' : 'updateTime'] = formatToDateTime(new Date());
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
|
||||
import { BasicColumn, BasicTableProps, FormProps } from '@jeesite/core/components/Table';
|
||||
import { myProjectRequirementListData } from '@jeesite/biz/api/biz/myProjectRequirement';
|
||||
|
||||
const { t } = useI18n('biz.myProjectRequirement');
|
||||
|
||||
const modalProps = {
|
||||
title: t('需求选择'),
|
||||
};
|
||||
|
||||
const searchForm: FormProps<MyProjectRequirement> = {
|
||||
baseColProps: { md: 8, lg: 6 },
|
||||
labelWidth: 90,
|
||||
schemas: [
|
||||
{
|
||||
label: t('记录时间起'),
|
||||
field: 'createTime_gte',
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
format: 'YYYY-MM-DD HH:mm',
|
||||
showTime: { format: 'HH:mm' },
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('记录时间止'),
|
||||
field: 'createTime_lte',
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
format: 'YYYY-MM-DD HH:mm',
|
||||
showTime: { format: 'HH:mm' },
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('需求编号'),
|
||||
field: 'requirementNo',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: t('需求标题'),
|
||||
field: 'requirementTitle',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: t('项目编号'),
|
||||
field: 'projectId',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: t('优先等级'),
|
||||
field: 'priority',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: t('需求状态'),
|
||||
field: 'requirementStatus',
|
||||
component: 'Input',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const tableColumns: BasicColumn<MyProjectRequirement>[] = [
|
||||
{
|
||||
title: t('记录时间'),
|
||||
dataIndex: 'createTime',
|
||||
key: 'a.create_time',
|
||||
sorter: true,
|
||||
width: 230,
|
||||
align: 'left',
|
||||
slot: 'firstColumn',
|
||||
},
|
||||
{
|
||||
title: t('需求编号'),
|
||||
dataIndex: 'requirementNo',
|
||||
key: 'a.requirement_no',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: t('需求标题'),
|
||||
dataIndex: 'requirementTitle',
|
||||
key: 'a.requirement_title',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: t('项目编号'),
|
||||
dataIndex: 'projectId',
|
||||
key: 'a.project_id',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: t('详细内容'),
|
||||
dataIndex: 'requirementContent',
|
||||
key: 'a.requirement_content',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: t('优先等级'),
|
||||
dataIndex: 'priority',
|
||||
key: 'a.priority',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: t('需求状态'),
|
||||
dataIndex: 'requirementStatus',
|
||||
key: 'a.requirement_status',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: t('负责人员'),
|
||||
dataIndex: 'handler',
|
||||
key: 'a.handler',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: t('计划完成时间'),
|
||||
dataIndex: 'planFinishTime',
|
||||
key: 'a.plan_finish_time',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: t('实际完成时间'),
|
||||
dataIndex: 'actualFinishTime',
|
||||
key: 'a.actual_finish_time',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: t('备注'),
|
||||
dataIndex: 'remark',
|
||||
key: 'a.remark',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: t('创建人'),
|
||||
dataIndex: 'createUser',
|
||||
key: 'a.create_user',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: t('更新时间'),
|
||||
dataIndex: 'updateTime',
|
||||
key: 'a.update_time',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'center',
|
||||
},
|
||||
];
|
||||
|
||||
const tableProps: BasicTableProps = {
|
||||
api: myProjectRequirementListData,
|
||||
beforeFetch: (params) => {
|
||||
params['isAll'] = true;
|
||||
return params;
|
||||
},
|
||||
columns: tableColumns,
|
||||
formConfig: searchForm,
|
||||
rowKey: 'requirementId',
|
||||
};
|
||||
|
||||
export default {
|
||||
modalProps,
|
||||
tableProps,
|
||||
itemCode: 'requirementId',
|
||||
itemName: 'requirementId',
|
||||
isShowCode: false,
|
||||
};
|
||||
@@ -42,7 +42,7 @@
|
||||
const { meta } = unref(router.currentRoute);
|
||||
const record = ref<MyProjectTask>({} as MyProjectTask);
|
||||
|
||||
const requirementListParams = ref<Recordable>({ projectId: '-1' });
|
||||
const requirementListParams = ref<Recordable>({ projectId: '-1',requirementStatus: '2' });
|
||||
|
||||
const getTitle = computed(() => ({
|
||||
icon: meta.icon || 'i-ant-design:book-outlined',
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
|
||||
import { BasicColumn, BasicTableProps, FormProps } from '@jeesite/core/components/Table';
|
||||
import { myProjectTaskListData } from '@jeesite/biz/api/biz/myProjectTask';
|
||||
|
||||
const { t } = useI18n('biz.myProjectTask');
|
||||
|
||||
const modalProps = {
|
||||
title: t('任务选择'),
|
||||
};
|
||||
|
||||
const searchForm: FormProps<MyProjectTask> = {
|
||||
baseColProps: { md: 8, lg: 6 },
|
||||
labelWidth: 90,
|
||||
schemas: [
|
||||
{
|
||||
label: t('记录时间起'),
|
||||
field: 'createTime_gte',
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
format: 'YYYY-MM-DD HH:mm',
|
||||
showTime: { format: 'HH:mm' },
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('记录时间止'),
|
||||
field: 'createTime_lte',
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
format: 'YYYY-MM-DD HH:mm',
|
||||
showTime: { format: 'HH:mm' },
|
||||
},
|
||||
},
|
||||
{
|
||||
label: t('任务名称'),
|
||||
field: 'taskName',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: t('项目标识'),
|
||||
field: 'projectId',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: t('需求标识'),
|
||||
field: 'requirementId',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: t('任务状态'),
|
||||
field: 'taskStatus',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: t('备注'),
|
||||
field: 'remark',
|
||||
component: 'Input',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const tableColumns: BasicColumn<MyProjectTask>[] = [
|
||||
{
|
||||
title: t('记录时间'),
|
||||
dataIndex: 'createTime',
|
||||
key: 'a.create_time',
|
||||
sorter: true,
|
||||
width: 230,
|
||||
align: 'left',
|
||||
slot: 'firstColumn',
|
||||
},
|
||||
{
|
||||
title: t('任务名称'),
|
||||
dataIndex: 'taskName',
|
||||
key: 'a.task_name',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: t('项目标识'),
|
||||
dataIndex: 'projectId',
|
||||
key: 'a.project_id',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: t('需求标识'),
|
||||
dataIndex: 'requirementId',
|
||||
key: 'a.requirement_id',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: t('任务状态'),
|
||||
dataIndex: 'taskStatus',
|
||||
key: 'a.task_status',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: t('负责人员'),
|
||||
dataIndex: 'handler',
|
||||
key: 'a.handler',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: t('计划开始'),
|
||||
dataIndex: 'planStartTime',
|
||||
key: 'a.plan_start_time',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: t('计划结束'),
|
||||
dataIndex: 'planEndTime',
|
||||
key: 'a.plan_end_time',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: t('实际开始'),
|
||||
dataIndex: 'actualStartTime',
|
||||
key: 'a.actual_start_time',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: t('实际结束'),
|
||||
dataIndex: 'actualEndTime',
|
||||
key: 'a.actual_end_time',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: t('工时'),
|
||||
dataIndex: 'workHours',
|
||||
key: 'a.work_hours',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'right',
|
||||
},
|
||||
{
|
||||
title: t('备注'),
|
||||
dataIndex: 'remark',
|
||||
key: 'a.remark',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: t('创建人员'),
|
||||
dataIndex: 'createUser',
|
||||
key: 'a.create_user',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: t('更新时间'),
|
||||
dataIndex: 'updateTime',
|
||||
key: 'a.update_time',
|
||||
sorter: true,
|
||||
width: 130,
|
||||
align: 'center',
|
||||
},
|
||||
];
|
||||
|
||||
const tableProps: BasicTableProps = {
|
||||
api: myProjectTaskListData,
|
||||
beforeFetch: (params) => {
|
||||
params['isAll'] = true;
|
||||
return params;
|
||||
},
|
||||
columns: tableColumns,
|
||||
formConfig: searchForm,
|
||||
rowKey: 'taskId',
|
||||
};
|
||||
|
||||
export default {
|
||||
modalProps,
|
||||
tableProps,
|
||||
itemCode: 'taskId',
|
||||
itemName: 'taskId',
|
||||
isShowCode: false,
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
<template>
|
||||
<PageWrapper :contentFullHeight="true" :dense="true" title="false" contentClass="my-screen-page-wrapper">
|
||||
<div class="my-screen-page">
|
||||
<header class="my-screen-panel my-screen-panel--header">
|
||||
<ChartTop />
|
||||
@@ -22,37 +23,56 @@
|
||||
</aside>
|
||||
</section>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="BizMyScreen">
|
||||
import { PageWrapper } from '@jeesite/core/components/Page';
|
||||
import ChartTop from './components/ChartTop.vue';
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@dark-bg: #141414;
|
||||
@desktop-page-gap: 12px;
|
||||
@desktop-page-padding: 0;
|
||||
@desktop-card-radius: 10px;
|
||||
@desktop-card-border: 1px solid rgb(226 232 240);
|
||||
@desktop-card-shadow: 0 1px 3px rgb(15 23 42 / 0.06);
|
||||
@desktop-dark-border: rgb(51 65 85);
|
||||
|
||||
.my-screen-page-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
padding: 0 !important;
|
||||
overflow: hidden !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.my-screen-page {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
padding: 0;
|
||||
gap: @desktop-page-gap;
|
||||
padding: @desktop-page-padding;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
border-radius: 10px;
|
||||
border-radius: @desktop-card-radius;
|
||||
}
|
||||
|
||||
.my-screen-panel {
|
||||
min-height: 0;
|
||||
padding: 8px 12px 12px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgb(226 232 240);
|
||||
border-radius: @desktop-card-radius;
|
||||
border: @desktop-card-border;
|
||||
background: rgb(255, 255, 255);
|
||||
box-shadow: 0 1px 3px rgb(15 23 42 / 0.06);
|
||||
box-shadow: @desktop-card-shadow;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -72,9 +92,9 @@
|
||||
flex: 1 1 90%;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
gap: @desktop-page-gap;
|
||||
background: transparent;
|
||||
border-radius: 10px;
|
||||
border-radius: @desktop-card-radius;
|
||||
}
|
||||
|
||||
.my-screen-left {
|
||||
@@ -83,7 +103,7 @@
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
gap: @desktop-page-gap;
|
||||
}
|
||||
|
||||
.my-screen-right {
|
||||
@@ -92,7 +112,7 @@
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
gap: @desktop-page-gap;
|
||||
}
|
||||
|
||||
.my-screen-left-top {
|
||||
@@ -104,7 +124,7 @@
|
||||
flex: 1 1 0;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
gap: @desktop-page-gap;
|
||||
}
|
||||
|
||||
.my-screen-left-middle .my-screen-panel,
|
||||
@@ -131,9 +151,8 @@
|
||||
background: @dark-bg !important;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .my-screen-panel,
|
||||
html[data-theme='dark'] .my-screen-panel {
|
||||
border-color: rgb(51 65 85);
|
||||
border-color: @desktop-dark-border;
|
||||
background: @dark-bg !important;
|
||||
color: rgb(203 213 225);
|
||||
box-shadow: none;
|
||||
@@ -145,8 +164,9 @@
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.my-screen-page {
|
||||
height: auto;
|
||||
min-height: 100%;
|
||||
flex: 1 1 auto;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.my-screen-panel--header {
|
||||
|
||||
@@ -93,11 +93,14 @@
|
||||
});
|
||||
};
|
||||
|
||||
const loadComponent = (vueName: string) => {
|
||||
const loadComponent = (vueName: string): Component => {
|
||||
return defineAsyncComponent({
|
||||
loader: () => import(`./components/${vueName}.vue`),
|
||||
delay: 200,
|
||||
timeout: 5000,
|
||||
onError(error) {
|
||||
console.error('加载组件失败', error);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -132,7 +135,9 @@
|
||||
await getChartList();
|
||||
|
||||
const newComponentMap: ComponentMap = {};
|
||||
const uniqueComponents = [...new Set(chartData.value.map((item) => item.vueName))];
|
||||
const uniqueComponents = [...new Set(chartData.value.map((item) => item.vueName))].filter(
|
||||
(vueName) => vueName && vueName !== 'ChartTop',
|
||||
);
|
||||
for (const vueName of uniqueComponents) {
|
||||
if (vueName) {
|
||||
newComponentMap[vueName] = loadComponent(vueName);
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, onMounted } from 'vue';
|
||||
import { ref, watch, onMounted, defineAsyncComponent } from 'vue';
|
||||
import type { Component } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import ChartTop from './components/ChartTop.vue';
|
||||
@@ -68,14 +68,15 @@
|
||||
});
|
||||
};
|
||||
|
||||
const loadComponent = async (vueName: string): Promise<Component | null> => {
|
||||
try {
|
||||
const module = await import(`./components/${vueName}.vue`);
|
||||
return module.default;
|
||||
} catch (error) {
|
||||
const loadComponent = (vueName: string): Component => {
|
||||
return defineAsyncComponent({
|
||||
loader: () => import(`./components/${vueName}.vue`),
|
||||
delay: 200,
|
||||
timeout: 5000,
|
||||
onError(error) {
|
||||
console.error('加载组件失败', error);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
async function getChartList() {
|
||||
@@ -97,7 +98,9 @@
|
||||
await getChartList();
|
||||
|
||||
const newComponentMap: ComponentMap = {};
|
||||
const uniqueComponents = [...new Set(chartData.value.map((item) => item.vueName))];
|
||||
const uniqueComponents = [...new Set(chartData.value.map((item) => item.vueName))].filter(
|
||||
(vueName) => vueName && vueName !== 'ChartTop',
|
||||
);
|
||||
for (const vueName of uniqueComponents) {
|
||||
if (vueName) {
|
||||
newComponentMap[vueName] = loadComponent(vueName);
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, onMounted } from 'vue';
|
||||
import { ref, watch, onMounted, defineAsyncComponent } from 'vue';
|
||||
import type { Component } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import ChartTop from './components/ChartTop.vue';
|
||||
@@ -68,14 +68,15 @@
|
||||
});
|
||||
};
|
||||
|
||||
const loadComponent = async (vueName: string): Promise<Component | null> => {
|
||||
try {
|
||||
const module = await import(`./components/${vueName}.vue`);
|
||||
return module.default;
|
||||
} catch (error) {
|
||||
const loadComponent = (vueName: string): Component => {
|
||||
return defineAsyncComponent({
|
||||
loader: () => import(`./components/${vueName}.vue`),
|
||||
delay: 200,
|
||||
timeout: 5000,
|
||||
onError(error) {
|
||||
console.error('加载组件失败', error);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
async function getChartList() {
|
||||
@@ -97,7 +98,9 @@
|
||||
await getChartList();
|
||||
|
||||
const newComponentMap: ComponentMap = {};
|
||||
const uniqueComponents = [...new Set(chartData.value.map((item) => item.vueName))];
|
||||
const uniqueComponents = [...new Set(chartData.value.map((item) => item.vueName))].filter(
|
||||
(vueName) => vueName && vueName !== 'ChartTop',
|
||||
);
|
||||
for (const vueName of uniqueComponents) {
|
||||
if (vueName) {
|
||||
newComponentMap[vueName] = loadComponent(vueName);
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, onMounted } from 'vue';
|
||||
import { ref, watch, onMounted, defineAsyncComponent } from 'vue';
|
||||
import type { Component } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import ChartTop from './components/ChartTop.vue';
|
||||
@@ -80,14 +80,15 @@
|
||||
});
|
||||
};
|
||||
|
||||
const loadComponent = async (vueName: string): Promise<Component | null> => {
|
||||
try {
|
||||
const module = await import(`./components/${vueName}.vue`);
|
||||
return module.default;
|
||||
} catch (error) {
|
||||
const loadComponent = (vueName: string): Component => {
|
||||
return defineAsyncComponent({
|
||||
loader: () => import(`./components/${vueName}.vue`),
|
||||
delay: 200,
|
||||
timeout: 5000,
|
||||
onError(error) {
|
||||
console.error('加载组件失败', error);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
async function getChartList() {
|
||||
@@ -109,7 +110,9 @@
|
||||
await getChartList();
|
||||
|
||||
const newComponentMap: ComponentMap = {};
|
||||
const uniqueComponents = [...new Set(chartData.value.map((item) => item.vueName))];
|
||||
const uniqueComponents = [...new Set(chartData.value.map((item) => item.vueName))].filter(
|
||||
(vueName) => vueName && vueName !== 'ChartTop',
|
||||
);
|
||||
for (const vueName of uniqueComponents) {
|
||||
if (vueName) {
|
||||
newComponentMap[vueName] = loadComponent(vueName);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<template>
|
||||
<PageWrapper>
|
||||
<template #headerContent>
|
||||
|
||||
</template>
|
||||
<PageWrapper :contentFullHeight="true" :dense="true" title="false" contentClass="about-page-wrapper">
|
||||
<template #headerContent> </template>
|
||||
<div class="jeesite-workbench">
|
||||
<div class="workbench-layout">
|
||||
<div class="workbench-top">10% 区域</div>
|
||||
@@ -34,28 +32,48 @@
|
||||
|
||||
<style lang="less">
|
||||
@dark-bg: #141414;
|
||||
@desktop-page-gap: 12px;
|
||||
@desktop-page-padding: 0;
|
||||
@desktop-card-radius: 10px;
|
||||
@desktop-card-border: 1px solid rgb(226 232 240);
|
||||
@desktop-card-shadow: 0 1px 3px rgb(15 23 42 / 0.06);
|
||||
@desktop-dark-border: rgb(51 65 85);
|
||||
|
||||
.about-page-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
padding: 0 !important;
|
||||
overflow: hidden !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.jeesite-workbench {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
margin: 0;
|
||||
background: #FFFFFF;
|
||||
border-radius: 10px;
|
||||
background: #ffffff;
|
||||
border-radius: @desktop-card-radius;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-layout {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
gap: @desktop-page-gap;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
padding: 4px;
|
||||
padding: @desktop-page-padding;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
border-radius: 10px;
|
||||
border-radius: @desktop-card-radius;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-top {
|
||||
@@ -66,7 +84,7 @@
|
||||
.jeesite-workbench .workbench-row {
|
||||
display: flex;
|
||||
flex: 0 0 30%;
|
||||
gap: 12px;
|
||||
gap: @desktop-page-gap;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
@@ -75,9 +93,10 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgb(226 232 240);
|
||||
background: #FFFFFF;
|
||||
border-radius: @desktop-card-radius;
|
||||
border: @desktop-card-border;
|
||||
background: #ffffff;
|
||||
box-shadow: @desktop-card-shadow;
|
||||
color: rgb(71 85 105);
|
||||
}
|
||||
|
||||
@@ -94,8 +113,9 @@
|
||||
|
||||
html[data-theme='dark'] .jeesite-workbench .workbench-top,
|
||||
html[data-theme='dark'] .jeesite-workbench .workbench-col {
|
||||
border-color: rgb(51 65 85);
|
||||
border-color: @desktop-dark-border;
|
||||
background: @dark-bg !important;
|
||||
color: rgb(226 232 240);
|
||||
box-shadow: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -43,6 +43,10 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@analysis-dark-bg: rgb(20, 20, 20);
|
||||
@analysis-dark-hover-bg: rgb(30 41 59);
|
||||
@analysis-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.biz-apps-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -122,7 +126,7 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .biz-apps-card {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
@@ -131,12 +135,13 @@
|
||||
|
||||
.biz-apps-item {
|
||||
border-color: rgb(51 65 85);
|
||||
background: rgb(20, 20, 20);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
|
||||
&:hover {
|
||||
border-color: rgb(96 165 250);
|
||||
box-shadow: 0 14px 32px rgb(37 99 235 / 22%);
|
||||
background: @analysis-dark-hover-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
}
|
||||
|
||||
&__name {
|
||||
|
||||
@@ -276,6 +276,10 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@analysis-dark-bg: rgb(20, 20, 20);
|
||||
@analysis-dark-hover-bg: rgb(30 41 59);
|
||||
@analysis-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.host-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -413,7 +417,7 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .host-card {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
@@ -438,20 +442,21 @@
|
||||
}
|
||||
|
||||
.host-gauge-panel {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
}
|
||||
|
||||
.metric-item {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
|
||||
&__label {
|
||||
color: rgb(148 163 184);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 12px 28px rgb(96 165 250 / 20%);
|
||||
background: @analysis-dark-hover-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +206,9 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@dark-bg: #141414;
|
||||
@analysis-dark-bg: rgb(20, 20, 20);
|
||||
@analysis-dark-hover-bg: rgb(30 41 59);
|
||||
@analysis-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.notice-card {
|
||||
width: 100%;
|
||||
@@ -591,7 +593,7 @@
|
||||
|
||||
html[data-theme='dark'] .notice-card {
|
||||
box-shadow: none;
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
@@ -616,15 +618,27 @@
|
||||
.table-container {
|
||||
.el-table {
|
||||
--el-table-border-color: transparent;
|
||||
--el-table-header-bg-color: rgb(20, 20, 20);
|
||||
--el-table-header-bg-color: @analysis-dark-bg;
|
||||
--el-table-tr-bg-color: transparent;
|
||||
--el-table-row-hover-bg-color: rgb(30 41 59);
|
||||
--el-table-row-hover-bg-color: @analysis-dark-hover-bg;
|
||||
--el-table-text-color: rgb(148 163 184);
|
||||
--el-table-header-text-color: rgb(226 232 240);
|
||||
background: transparent;
|
||||
|
||||
th.el-table__cell {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
}
|
||||
|
||||
.el-loading-mask {
|
||||
background-color: rgb(20 20 20 / 72%);
|
||||
}
|
||||
|
||||
.el-loading-spinner .path {
|
||||
stroke: rgb(147 197 253);
|
||||
}
|
||||
|
||||
.el-loading-spinner .el-loading-text {
|
||||
color: rgb(203 213 225);
|
||||
}
|
||||
|
||||
th.el-table__cell,
|
||||
@@ -650,25 +664,25 @@
|
||||
|
||||
&__content-panel,
|
||||
&__attachments-panel {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
}
|
||||
|
||||
&__attachments-panel {
|
||||
border-color: rgb(51 65 85);
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
}
|
||||
|
||||
&__content {
|
||||
color: rgb(226 232 240);
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
border-color: rgb(51 65 85);
|
||||
}
|
||||
|
||||
&__attachment-item,
|
||||
&__attachments-empty {
|
||||
border-color: rgb(71 85 105);
|
||||
background: rgb(20, 20, 20);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
color: rgb(226 232 240);
|
||||
}
|
||||
|
||||
@@ -686,8 +700,8 @@
|
||||
|
||||
&__attachment-item:hover {
|
||||
border-color: rgb(96 165 250);
|
||||
background: rgb(37 99 235 / 22%);
|
||||
box-shadow: 0 14px 32px rgb(37 99 235 / 22%);
|
||||
background: @analysis-dark-hover-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
color: rgb(241 245 249);
|
||||
}
|
||||
|
||||
@@ -698,27 +712,27 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .notice-info-dialog {
|
||||
--el-bg-color: rgb(20, 20, 20);
|
||||
--el-dialog-bg-color: rgb(20, 20, 20);
|
||||
--el-fill-color-blank: rgb(20, 20, 20);
|
||||
--el-bg-color: @analysis-dark-bg;
|
||||
--el-dialog-bg-color: @analysis-dark-bg;
|
||||
--el-fill-color-blank: @analysis-dark-bg;
|
||||
|
||||
.el-dialog {
|
||||
background: rgb(20, 20, 20) !important;
|
||||
--el-dialog-bg-color: rgb(20, 20, 20);
|
||||
--el-bg-color: rgb(20, 20, 20);
|
||||
--el-fill-color-blank: rgb(20, 20, 20);
|
||||
box-shadow: 0 14px 36px rgb(0 0 0 / 42%);
|
||||
background: @analysis-dark-bg !important;
|
||||
--el-dialog-bg-color: @analysis-dark-bg;
|
||||
--el-bg-color: @analysis-dark-bg;
|
||||
--el-fill-color-blank: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
}
|
||||
|
||||
.el-dialog__wrapper,
|
||||
.el-overlay-dialog,
|
||||
.el-dialog__content {
|
||||
background: rgb(20, 20, 20) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
}
|
||||
|
||||
.el-dialog__header {
|
||||
border-bottom: 1px solid rgb(51 65 85) !important;
|
||||
background: rgb(20, 20, 20) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
}
|
||||
|
||||
.el-dialog__title {
|
||||
@@ -730,14 +744,14 @@
|
||||
}
|
||||
|
||||
.el-dialog__body {
|
||||
background: rgb(20, 20, 20) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
}
|
||||
|
||||
.el-dialog__header,
|
||||
.el-dialog__body,
|
||||
.el-dialog__footer {
|
||||
--el-bg-color: rgb(20, 20, 20);
|
||||
--el-fill-color-blank: rgb(20, 20, 20);
|
||||
--el-bg-color: @analysis-dark-bg;
|
||||
--el-fill-color-blank: @analysis-dark-bg;
|
||||
}
|
||||
|
||||
.el-divider {
|
||||
@@ -746,7 +760,7 @@
|
||||
|
||||
.notice-dialog {
|
||||
&__attachments-title {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
color: rgb(226 232 240);
|
||||
}
|
||||
|
||||
|
||||
@@ -196,6 +196,10 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@analysis-dark-bg: rgb(20, 20, 20);
|
||||
@analysis-dark-hover-bg: rgb(30 41 59);
|
||||
@analysis-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.oper-log-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -369,7 +373,7 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .oper-log-card {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
@@ -378,8 +382,8 @@
|
||||
|
||||
.query-panel,
|
||||
.table-panel {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
}
|
||||
|
||||
.query-form {
|
||||
@@ -391,7 +395,7 @@
|
||||
:deep(.el-select__wrapper) {
|
||||
--el-fill-color-blank: rgb(20, 20, 20);
|
||||
--el-bg-color: rgb(20, 20, 20);
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
box-shadow: 0 0 0 1px rgb(71 85 105) inset;
|
||||
}
|
||||
|
||||
@@ -404,7 +408,7 @@
|
||||
:deep(.el-select-dropdown),
|
||||
:deep(.el-popper),
|
||||
:deep(.el-select__popper.el-popper) {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
border-color: rgb(51 65 85);
|
||||
}
|
||||
|
||||
@@ -415,7 +419,7 @@
|
||||
:deep(.el-select-dropdown__item.hover),
|
||||
:deep(.el-select-dropdown__item:hover),
|
||||
:deep(.el-select-dropdown__item.is-hovering) {
|
||||
background: rgb(30 41 59);
|
||||
background: @analysis-dark-hover-bg;
|
||||
color: rgb(241 245 249);
|
||||
}
|
||||
|
||||
@@ -453,28 +457,28 @@
|
||||
}
|
||||
|
||||
:deep(.el-button) {
|
||||
--el-fill-color-blank: rgb(30 41 59);
|
||||
--el-bg-color: rgb(30 41 59);
|
||||
--el-fill-color-blank: @analysis-dark-bg;
|
||||
--el-bg-color: @analysis-dark-bg;
|
||||
border-color: rgb(71 85 105);
|
||||
background: rgb(30 41 59);
|
||||
background: @analysis-dark-bg;
|
||||
color: rgb(226 232 240);
|
||||
}
|
||||
|
||||
:deep(.el-button:hover) {
|
||||
border-color: rgb(96 165 250);
|
||||
background: rgb(37 99 235 / 22%);
|
||||
background: @analysis-dark-hover-bg;
|
||||
color: rgb(241 245 249);
|
||||
}
|
||||
|
||||
:deep(.el-button--primary) {
|
||||
border-color: rgb(59 130 246);
|
||||
background: rgb(37 99 235);
|
||||
border-color: rgb(96 165 250);
|
||||
background: @analysis-dark-bg;
|
||||
color: rgb(248 250 252);
|
||||
}
|
||||
|
||||
:deep(.el-button--primary:hover) {
|
||||
border-color: rgb(96 165 250);
|
||||
background: rgb(59 130 246);
|
||||
background: @analysis-dark-hover-bg;
|
||||
color: rgb(248 250 252);
|
||||
}
|
||||
}
|
||||
@@ -482,15 +486,15 @@
|
||||
.table-panel {
|
||||
.el-table {
|
||||
--el-table-border-color: transparent;
|
||||
--el-table-header-bg-color: rgb(20, 20, 20);
|
||||
--el-table-header-bg-color: @analysis-dark-bg;
|
||||
--el-table-tr-bg-color: transparent;
|
||||
--el-table-row-hover-bg-color: rgb(30 41 59);
|
||||
--el-table-row-hover-bg-color: @analysis-dark-hover-bg;
|
||||
--el-table-text-color: rgb(148 163 184);
|
||||
--el-table-header-text-color: rgb(226 232 240);
|
||||
background: transparent;
|
||||
|
||||
th.el-table__cell {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
}
|
||||
|
||||
th.el-table__cell,
|
||||
@@ -499,11 +503,23 @@
|
||||
}
|
||||
|
||||
.el-table__footer-wrapper td.el-table__cell {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
border-top: 1px solid rgb(51 65 85);
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.el-loading-mask {
|
||||
background-color: rgb(20 20 20 / 72%);
|
||||
}
|
||||
|
||||
.el-loading-spinner .path {
|
||||
stroke: rgb(147 197 253);
|
||||
}
|
||||
|
||||
.el-loading-spinner .el-loading-text {
|
||||
color: rgb(203 213 225);
|
||||
}
|
||||
|
||||
.el-table__footer-wrapper .cell {
|
||||
color: rgb(226 232 240);
|
||||
}
|
||||
@@ -517,7 +533,7 @@
|
||||
:deep(.el-pagination) {
|
||||
--el-pagination-text-color: rgb(226 232 240);
|
||||
--el-pagination-button-color: rgb(226 232 240);
|
||||
--el-pagination-button-bg-color: rgb(30 41 59);
|
||||
--el-pagination-button-bg-color: @analysis-dark-bg;
|
||||
--el-pagination-hover-color: rgb(147 197 253);
|
||||
}
|
||||
|
||||
@@ -525,7 +541,7 @@
|
||||
:deep(.btn-next),
|
||||
:deep(.el-pager li),
|
||||
:deep(.el-pagination button) {
|
||||
background: rgb(30 41 59) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
color: rgb(226 232 240) !important;
|
||||
}
|
||||
|
||||
@@ -578,7 +594,7 @@
|
||||
html[data-theme='dark'] .el-select-dropdown__item.hover,
|
||||
html[data-theme='dark'] .el-select-dropdown__item:hover,
|
||||
html[data-theme='dark'] .el-select-dropdown__item.is-hovering {
|
||||
background: rgb(30 41 59) !important;
|
||||
background: @analysis-dark-hover-bg !important;
|
||||
color: rgb(241 245 249) !important;
|
||||
}
|
||||
|
||||
@@ -590,7 +606,7 @@
|
||||
html[data-theme='dark'] .el-pagination .btn-next,
|
||||
html[data-theme='dark'] .el-pagination .el-pager li,
|
||||
html[data-theme='dark'] .el-pagination button {
|
||||
background: rgb(30 41 59) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
color: rgb(226 232 240) !important;
|
||||
}
|
||||
|
||||
@@ -632,7 +648,7 @@
|
||||
|
||||
html[data-theme='dark'] .oper-log-card .el-input.is-disabled .el-input__wrapper,
|
||||
html[data-theme='dark'] .oper-log-card .el-select.is-disabled .el-select__wrapper {
|
||||
background: rgb(30 41 59) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .oper-log-card .el-input__suffix,
|
||||
@@ -644,16 +660,16 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .oper-log-card .query-form__actions .el-button {
|
||||
--el-button-bg-color: rgb(30 41 59) !important;
|
||||
--el-button-bg-color: @analysis-dark-bg !important;
|
||||
--el-button-border-color: rgb(71 85 105) !important;
|
||||
--el-button-text-color: rgb(226 232 240) !important;
|
||||
--el-button-hover-bg-color: rgb(37 99 235 / 22%) !important;
|
||||
--el-button-hover-bg-color: @analysis-dark-hover-bg !important;
|
||||
--el-button-hover-border-color: rgb(96 165 250) !important;
|
||||
--el-button-hover-text-color: rgb(241 245 249) !important;
|
||||
--el-button-active-bg-color: rgb(37 99 235 / 28%) !important;
|
||||
--el-button-active-bg-color: @analysis-dark-hover-bg !important;
|
||||
--el-button-active-border-color: rgb(96 165 250) !important;
|
||||
--el-button-active-text-color: rgb(241 245 249) !important;
|
||||
background: rgb(30 41 59) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
border-color: rgb(71 85 105) !important;
|
||||
color: rgb(226 232 240) !important;
|
||||
box-shadow: none !important;
|
||||
@@ -661,26 +677,26 @@
|
||||
|
||||
html[data-theme='dark'] .oper-log-card .query-form__actions .el-button:hover,
|
||||
html[data-theme='dark'] .oper-log-card .query-form__actions .el-button:focus {
|
||||
background: rgb(37 99 235 / 22%) !important;
|
||||
background: @analysis-dark-hover-bg !important;
|
||||
border-color: rgb(96 165 250) !important;
|
||||
color: rgb(241 245 249) !important;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .oper-log-card .query-form__actions .el-button--primary {
|
||||
--el-button-bg-color: rgb(37 99 235) !important;
|
||||
--el-button-border-color: rgb(59 130 246) !important;
|
||||
--el-button-bg-color: @analysis-dark-bg !important;
|
||||
--el-button-border-color: rgb(96 165 250) !important;
|
||||
--el-button-text-color: rgb(248 250 252) !important;
|
||||
--el-button-hover-bg-color: rgb(59 130 246) !important;
|
||||
--el-button-hover-bg-color: @analysis-dark-hover-bg !important;
|
||||
--el-button-hover-border-color: rgb(96 165 250) !important;
|
||||
--el-button-hover-text-color: rgb(248 250 252) !important;
|
||||
background: rgb(37 99 235) !important;
|
||||
border-color: rgb(59 130 246) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
border-color: rgb(96 165 250) !important;
|
||||
color: rgb(248 250 252) !important;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .oper-log-card .query-form__actions .el-button--primary:hover,
|
||||
html[data-theme='dark'] .oper-log-card .query-form__actions .el-button--primary:focus {
|
||||
background: rgb(59 130 246) !important;
|
||||
background: @analysis-dark-hover-bg !important;
|
||||
border-color: rgb(96 165 250) !important;
|
||||
color: rgb(248 250 252) !important;
|
||||
}
|
||||
|
||||
@@ -184,6 +184,9 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@analysis-dark-bg: rgb(20, 20, 20);
|
||||
@analysis-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.province-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -241,7 +244,7 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .province-card {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
@@ -253,8 +256,8 @@
|
||||
}
|
||||
|
||||
.province-chart-panel {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -157,6 +157,10 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@analysis-dark-bg: rgb(20, 20, 20);
|
||||
@analysis-dark-hover-bg: rgb(30 41 59);
|
||||
@analysis-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.quick-login-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -292,7 +296,7 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .quick-login-card {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
@@ -301,12 +305,13 @@
|
||||
|
||||
.quick-login-item {
|
||||
border-color: rgb(51 65 85);
|
||||
background: rgb(20, 20, 20);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
|
||||
&:hover {
|
||||
border-color: rgb(96 165 250);
|
||||
box-shadow: 0 14px 32px rgb(37 99 235 / 22%);
|
||||
background: @analysis-dark-hover-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
}
|
||||
|
||||
&__name {
|
||||
@@ -314,7 +319,7 @@
|
||||
}
|
||||
|
||||
&__image-wrap {
|
||||
background: rgb(30 41 59);
|
||||
background: @analysis-dark-bg;
|
||||
border-color: rgb(59 130 246 / 35%);
|
||||
box-shadow: 0 6px 14px rgb(37 99 235 / 16%);
|
||||
}
|
||||
|
||||
@@ -255,6 +255,10 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@analysis-dark-bg: rgb(20, 20, 20);
|
||||
@analysis-dark-hover-bg: rgb(30 41 59);
|
||||
@analysis-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.notice-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -568,7 +572,7 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .notice-card {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
@@ -593,15 +597,27 @@
|
||||
.table-container {
|
||||
.el-table {
|
||||
--el-table-border-color: transparent;
|
||||
--el-table-header-bg-color: rgb(20, 20, 20);
|
||||
--el-table-header-bg-color: @analysis-dark-bg;
|
||||
--el-table-tr-bg-color: transparent;
|
||||
--el-table-row-hover-bg-color: rgb(30 41 59);
|
||||
--el-table-row-hover-bg-color: @analysis-dark-hover-bg;
|
||||
--el-table-text-color: rgb(148 163 184);
|
||||
--el-table-header-text-color: rgb(226 232 240);
|
||||
background: transparent;
|
||||
|
||||
th.el-table__cell {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
}
|
||||
|
||||
.el-loading-mask {
|
||||
background-color: rgb(20 20 20 / 72%);
|
||||
}
|
||||
|
||||
.el-loading-spinner .path {
|
||||
stroke: rgb(147 197 253);
|
||||
}
|
||||
|
||||
.el-loading-spinner .el-loading-text {
|
||||
color: rgb(203 213 225);
|
||||
}
|
||||
|
||||
th.el-table__cell,
|
||||
@@ -629,7 +645,7 @@
|
||||
&__form-panel,
|
||||
&__content,
|
||||
&__section-title {
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
}
|
||||
|
||||
&__content {
|
||||
@@ -649,7 +665,7 @@
|
||||
&__textarea :deep(.el-textarea__inner) {
|
||||
border: 1px solid rgb(71 85 105) !important;
|
||||
border-color: rgb(71 85 105);
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
color: rgb(226 232 240);
|
||||
box-shadow: none !important;
|
||||
}
|
||||
@@ -668,38 +684,38 @@
|
||||
|
||||
&__textarea :deep(.el-input__count) {
|
||||
color: rgb(148 163 184);
|
||||
background: rgb(20, 20, 20);
|
||||
background: @analysis-dark-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .todo-info-dialog {
|
||||
--el-bg-color: rgb(20, 20, 20);
|
||||
--el-dialog-bg-color: rgb(20, 20, 20);
|
||||
--el-fill-color-blank: rgb(20, 20, 20);
|
||||
--el-bg-color: @analysis-dark-bg;
|
||||
--el-dialog-bg-color: @analysis-dark-bg;
|
||||
--el-fill-color-blank: @analysis-dark-bg;
|
||||
|
||||
.el-dialog {
|
||||
background: rgb(20, 20, 20) !important;
|
||||
--el-dialog-bg-color: rgb(20, 20, 20);
|
||||
--el-bg-color: rgb(20, 20, 20);
|
||||
--el-fill-color-blank: rgb(20, 20, 20);
|
||||
box-shadow: 0 14px 36px rgb(0 0 0 / 42%);
|
||||
background: @analysis-dark-bg !important;
|
||||
--el-dialog-bg-color: @analysis-dark-bg;
|
||||
--el-bg-color: @analysis-dark-bg;
|
||||
--el-fill-color-blank: @analysis-dark-bg;
|
||||
box-shadow: @analysis-dark-shadow;
|
||||
}
|
||||
|
||||
.el-dialog__wrapper,
|
||||
.el-overlay-dialog,
|
||||
.el-dialog__content {
|
||||
background: rgb(20, 20, 20) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
}
|
||||
|
||||
.el-dialog__header {
|
||||
border-bottom: 1px solid rgb(51 65 85) !important;
|
||||
background: rgb(20, 20, 20) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
}
|
||||
|
||||
.el-dialog__body,
|
||||
.el-dialog__footer {
|
||||
background: rgb(20, 20, 20) !important;
|
||||
background: @analysis-dark-bg !important;
|
||||
}
|
||||
|
||||
.el-textarea,
|
||||
@@ -708,8 +724,8 @@
|
||||
--el-input-border-color: rgb(71 85 105);
|
||||
--el-input-hover-border-color: rgb(96 165 250);
|
||||
--el-input-focus-border-color: rgb(96 165 250);
|
||||
--el-fill-color-blank: rgb(20, 20, 20);
|
||||
background: rgb(20, 20, 20) !important;
|
||||
--el-fill-color-blank: @analysis-dark-bg;
|
||||
background: @analysis-dark-bg !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
@@ -728,8 +744,8 @@
|
||||
.el-dialog__header,
|
||||
.el-dialog__body,
|
||||
.el-dialog__footer {
|
||||
--el-bg-color: rgb(20, 20, 20);
|
||||
--el-fill-color-blank: rgb(20, 20, 20);
|
||||
--el-bg-color: @analysis-dark-bg;
|
||||
--el-fill-color-blank: @analysis-dark-bg;
|
||||
}
|
||||
|
||||
.el-divider {
|
||||
@@ -742,26 +758,26 @@
|
||||
|
||||
.todo-dialog__footer {
|
||||
.el-button:not(.el-button--primary) {
|
||||
border-color: rgb(71 85 105);
|
||||
background: rgb(30 41 59);
|
||||
border-color: rgb(96 165 250);
|
||||
background: @analysis-dark-bg;
|
||||
color: rgb(226 232 240);
|
||||
}
|
||||
|
||||
.el-button:not(.el-button--primary):hover {
|
||||
border-color: rgb(96 165 250);
|
||||
background: rgb(37 99 235 / 22%);
|
||||
background: @analysis-dark-hover-bg;
|
||||
color: rgb(241 245 249);
|
||||
}
|
||||
|
||||
.el-button--primary {
|
||||
border-color: rgb(59 130 246);
|
||||
background: rgb(37 99 235);
|
||||
border-color: rgb(96 165 250);
|
||||
background: @analysis-dark-bg;
|
||||
color: rgb(248 250 252);
|
||||
}
|
||||
|
||||
.el-button--primary:hover {
|
||||
border-color: rgb(96 165 250);
|
||||
background: rgb(59 130 246);
|
||||
background: @analysis-dark-hover-bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,12 @@
|
||||
</script>
|
||||
<style lang="less">
|
||||
@dark-bg: #141414;
|
||||
@desktop-page-gap: 12px;
|
||||
@desktop-page-padding: 0;
|
||||
@desktop-card-radius: 10px;
|
||||
@desktop-card-border: 1px solid rgb(226 232 240);
|
||||
@desktop-card-shadow: 0 1px 3px rgb(15 23 42 / 0.06);
|
||||
@desktop-dark-border: rgb(51 65 85);
|
||||
|
||||
.analysis-page-wrapper {
|
||||
display: flex;
|
||||
@@ -97,18 +103,19 @@
|
||||
--analysis-card-title-padding: 8px 16px;
|
||||
--analysis-card-content-padding: 8px 12px 12px;
|
||||
--analysis-card-item-gap: 8px;
|
||||
--analysis-card-radius: 10px;
|
||||
--analysis-gap: @desktop-page-gap;
|
||||
--analysis-card-radius: @desktop-card-radius;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
min-height: 0;
|
||||
gap: var(--analysis-gap);
|
||||
padding: 0;
|
||||
padding: @desktop-page-padding;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
border-radius: 10px;
|
||||
border-radius: @desktop-card-radius;
|
||||
}
|
||||
|
||||
.mySpring-analysis .analysis-left,
|
||||
@@ -148,16 +155,16 @@
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
border-radius: var(--analysis-card-radius);
|
||||
border: 1px solid rgb(226 232 240);
|
||||
border: @desktop-card-border;
|
||||
background: rgb(255, 255, 255);
|
||||
box-shadow: 0 1px 3px rgb(15 23 42 / 0.06);
|
||||
box-shadow: @desktop-card-shadow;
|
||||
overflow: hidden;
|
||||
color: rgb(71 85 105);
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .mySpring-analysis .analysis-panel {
|
||||
border-color: rgb(51 65 85);
|
||||
border-color: @desktop-dark-border;
|
||||
background: @dark-bg !important;
|
||||
color: rgb(203 213 225);
|
||||
box-shadow: none;
|
||||
@@ -171,7 +178,7 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .mySpring-analysis {
|
||||
border-radius: 10px;
|
||||
border-radius: @desktop-card-radius;
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .mySpring-analysis,
|
||||
|
||||
@@ -0,0 +1,585 @@
|
||||
<template>
|
||||
<div ref="contractCardRef" class="contract-info-card">
|
||||
<div class="card-title">
|
||||
<span>项目合同</span>
|
||||
<el-button class="card-title__more" link type="primary" @click="goMore">更多</el-button>
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
<div class="contract-overview">
|
||||
<div class="task-chart-panel task-chart-panel--pie">
|
||||
<div ref="pieChartRef" class="task-chart"></div>
|
||||
</div>
|
||||
|
||||
<div class="task-chart-panel task-chart-panel--bar">
|
||||
<div ref="barChartRef" class="task-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import * as echarts from 'echarts';
|
||||
import { MyProjectContract, myProjectContractListAll } from '@jeesite/biz/api/biz/myProjectContract';
|
||||
import { DictData, dictDataListData } from '@jeesite/core/api/sys/dictData';
|
||||
import { useUserStore } from '@jeesite/core/store/modules/user';
|
||||
import { firstCurrentYear, formatToDate } from '@jeesite/core/utils/dateUtil';
|
||||
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
const userinfo = computed(() => userStore.getUserInfo);
|
||||
|
||||
const contractCardRef = ref<HTMLElement>();
|
||||
const pieChartRef = ref<HTMLElement>();
|
||||
const barChartRef = ref<HTMLElement>();
|
||||
const sourceData = ref<MyProjectContract[]>([]);
|
||||
const statusDict = ref<DictData[]>([]);
|
||||
|
||||
const STATUS_COLORS = ['#3B82F6', '#10B981', '#F97316', '#EC4899', '#8B5CF6', '#06B6D4'];
|
||||
let pieChartInstance: echarts.ECharts | null = null;
|
||||
let barChartInstance: echarts.ECharts | null = null;
|
||||
let resizeObserver: ResizeObserver | null = null;
|
||||
let themeObserver: MutationObserver | null = null;
|
||||
|
||||
function goMore() {
|
||||
router.push('/biz/myProjectContract/list');
|
||||
}
|
||||
|
||||
const pieChartData = computed(() => {
|
||||
if (!statusDict.value.length) {
|
||||
const fallbackMap = new Map<string, number>();
|
||||
sourceData.value.forEach((item) => {
|
||||
const label = item.contractStatus || '未设置';
|
||||
fallbackMap.set(label, (fallbackMap.get(label) || 0) + 1);
|
||||
});
|
||||
return Array.from(fallbackMap.entries()).map(([name, value], index) => ({
|
||||
name,
|
||||
value,
|
||||
itemStyle: { color: STATUS_COLORS[index % STATUS_COLORS.length] },
|
||||
}));
|
||||
}
|
||||
|
||||
const countMap = new Map<string, number>();
|
||||
sourceData.value.forEach((item) => {
|
||||
const key = item.contractStatus || 'unknown';
|
||||
countMap.set(key, (countMap.get(key) || 0) + 1);
|
||||
});
|
||||
|
||||
return statusDict.value
|
||||
.map((item, index) => ({
|
||||
name: item.dictLabelRaw,
|
||||
value: countMap.get(item.dictValue || '') || 0,
|
||||
itemStyle: { color: STATUS_COLORS[index % STATUS_COLORS.length] },
|
||||
}))
|
||||
.filter((item) => item.value > 0);
|
||||
});
|
||||
|
||||
const barChartData = computed(() => {
|
||||
const statusItems = statusDict.value.length
|
||||
? statusDict.value.map((item, index) => ({
|
||||
key: item.dictValue,
|
||||
label: item.dictLabelRaw,
|
||||
color: STATUS_COLORS[index % STATUS_COLORS.length],
|
||||
}))
|
||||
: [];
|
||||
|
||||
const monthStatusMap = new Map<string, Map<string, number>>();
|
||||
const monthOrderMap = new Map<string, number>();
|
||||
|
||||
sourceData.value.forEach((item) => {
|
||||
if (!item.signDate) return;
|
||||
const date = new Date(item.signDate);
|
||||
if (Number.isNaN(date.getTime())) return;
|
||||
const monthLabel = `${date.getMonth() + 1}月`;
|
||||
monthOrderMap.set(monthLabel, date.getMonth() + 1);
|
||||
const statusKey = item.contractStatus || 'unknown';
|
||||
if (!monthStatusMap.has(monthLabel)) {
|
||||
monthStatusMap.set(monthLabel, new Map<string, number>());
|
||||
}
|
||||
const monthMap = monthStatusMap.get(monthLabel)!;
|
||||
monthMap.set(statusKey, (monthMap.get(statusKey) || 0) + 1);
|
||||
});
|
||||
|
||||
const months = Array.from(monthStatusMap.keys()).sort((a, b) => {
|
||||
return (monthOrderMap.get(a) || 0) - (monthOrderMap.get(b) || 0);
|
||||
});
|
||||
|
||||
const totalByMonth = months.map((month) => {
|
||||
const monthMap = monthStatusMap.get(month);
|
||||
return Array.from(monthMap?.values() || []).reduce((sum, count) => sum + count, 0);
|
||||
});
|
||||
|
||||
const fallbackStatusMap = new Map<string, number>();
|
||||
sourceData.value.forEach((item) => {
|
||||
if (!statusDict.value.length) {
|
||||
const key = item.contractStatus || '未设置';
|
||||
fallbackStatusMap.set(key, (fallbackStatusMap.get(key) || 0) + 1);
|
||||
}
|
||||
});
|
||||
|
||||
const fallbackSeries = Array.from(fallbackStatusMap.keys()).map((key, index) => ({
|
||||
key,
|
||||
label: key,
|
||||
color: STATUS_COLORS[index % STATUS_COLORS.length],
|
||||
}));
|
||||
|
||||
return {
|
||||
months,
|
||||
totals: totalByMonth,
|
||||
statusItems: statusItems.length ? statusItems : fallbackSeries,
|
||||
monthStatusMap,
|
||||
};
|
||||
});
|
||||
|
||||
async function getDict() {
|
||||
try {
|
||||
statusDict.value = await dictDataListData({ dictType: 'contract_status' });
|
||||
} catch (error) {
|
||||
statusDict.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
async function getList() {
|
||||
try {
|
||||
const reqParams = {
|
||||
createTime_gte: firstCurrentYear(),
|
||||
createUser: userinfo.value.loginCode,
|
||||
};
|
||||
const res = await myProjectContractListAll(reqParams);
|
||||
sourceData.value = res || [];
|
||||
} catch (error) {
|
||||
sourceData.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
function renderPieChart() {
|
||||
if (!pieChartRef.value) return;
|
||||
if (!pieChartInstance) {
|
||||
pieChartInstance = echarts.init(pieChartRef.value);
|
||||
}
|
||||
|
||||
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
|
||||
const total = pieChartData.value.reduce((sum, item) => sum + Number(item.value || 0), 0);
|
||||
const data = total
|
||||
? pieChartData.value
|
||||
: statusDict.value.map((item, index) => ({
|
||||
name: item.dictLabelRaw,
|
||||
value: 0,
|
||||
itemStyle: { color: STATUS_COLORS[index % STATUS_COLORS.length] },
|
||||
}));
|
||||
const legendData = statusDict.value.length
|
||||
? statusDict.value.map((item) => item.dictLabelRaw)
|
||||
: pieChartData.value.map((item) => item.name);
|
||||
const series: echarts.SeriesOption[] = [];
|
||||
|
||||
if (!total) {
|
||||
series.push({
|
||||
name: '空态环',
|
||||
type: 'pie',
|
||||
radius: ['46%', '72%'],
|
||||
center: ['50%', '44%'],
|
||||
silent: true,
|
||||
legendHoverLink: false,
|
||||
tooltip: {
|
||||
show: false,
|
||||
},
|
||||
label: {
|
||||
show: false,
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
itemStyle: {
|
||||
color: isDark ? 'rgba(148, 163, 184, 0.18)' : 'rgba(203, 213, 225, 0.55)',
|
||||
borderRadius: 10,
|
||||
borderColor: isDark ? '#141414' : '#ffffff',
|
||||
borderWidth: 3,
|
||||
},
|
||||
data: [{ name: 'empty-ring', value: 1 }],
|
||||
});
|
||||
}
|
||||
|
||||
series.push({
|
||||
name: '合同状态',
|
||||
type: 'pie',
|
||||
radius: total ? ['46%', '72%'] : [0, 0],
|
||||
center: ['50%', '44%'],
|
||||
avoidLabelOverlap: true,
|
||||
minAngle: total ? 4 : 0,
|
||||
itemStyle: {
|
||||
borderRadius: 10,
|
||||
borderColor: isDark ? '#141414' : '#ffffff',
|
||||
borderWidth: 3,
|
||||
},
|
||||
label: {
|
||||
show: total,
|
||||
formatter: ({ name, value, percent }) => (total ? `${name}\n${value}项 / ${percent}%` : ''),
|
||||
color: isDark ? '#e2e8f0' : '#334155',
|
||||
fontSize: 12,
|
||||
},
|
||||
emphasis: {
|
||||
scale: true,
|
||||
scaleSize: 6,
|
||||
},
|
||||
data,
|
||||
silent: !total,
|
||||
labelLine: {
|
||||
show: total,
|
||||
},
|
||||
});
|
||||
|
||||
pieChartInstance.setOption({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
backgroundColor: isDark ? 'rgba(20, 20, 20, 0.96)' : 'rgba(255, 255, 255, 0.96)',
|
||||
borderColor: isDark ? 'rgb(51 65 85)' : 'rgb(226 232 240)',
|
||||
borderWidth: 1,
|
||||
textStyle: {
|
||||
color: isDark ? '#e2e8f0' : '#334155',
|
||||
},
|
||||
formatter: ({ name, value, percent }) => {
|
||||
if (!total) return `${name}<br/>数量:0`;
|
||||
return `${name}<br/>数量:${value}<br/>占比:${percent}%`;
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
show: legendData.length > 0,
|
||||
bottom: 4,
|
||||
left: 'center',
|
||||
itemWidth: 10,
|
||||
itemHeight: 10,
|
||||
data: legendData,
|
||||
textStyle: {
|
||||
color: isDark ? '#cbd5e1' : '#475569',
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
series,
|
||||
graphic: total
|
||||
? [
|
||||
{
|
||||
type: 'text',
|
||||
left: 'center',
|
||||
top: '34%',
|
||||
style: {
|
||||
text: '合同总数',
|
||||
fill: isDark ? '#94a3b8' : '#64748b',
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
left: 'center',
|
||||
top: '41%',
|
||||
style: {
|
||||
text: `${total}`,
|
||||
fill: isDark ? '#f8fafc' : '#0f172a',
|
||||
fontSize: 24,
|
||||
fontWeight: 700,
|
||||
},
|
||||
},
|
||||
]
|
||||
: [],
|
||||
});
|
||||
}
|
||||
|
||||
function renderBarChart() {
|
||||
if (!barChartRef.value) return;
|
||||
if (!barChartInstance) {
|
||||
barChartInstance = echarts.init(barChartRef.value);
|
||||
}
|
||||
|
||||
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
|
||||
const { months, totals, statusItems, monthStatusMap } = barChartData.value;
|
||||
const hasData = totals.some((item) => item > 0);
|
||||
const categories = months.length ? months : [];
|
||||
const series = statusItems.length
|
||||
? statusItems.map((status) => ({
|
||||
name: status.label,
|
||||
type: 'bar',
|
||||
stack: 'month-total',
|
||||
barWidth: '12%',
|
||||
itemStyle: {
|
||||
color: status.color,
|
||||
borderRadius: 0,
|
||||
},
|
||||
emphasis: {
|
||||
focus: 'series',
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'inside',
|
||||
formatter: ({ value }) => (Number(value) > 0 ? `${value}` : ''),
|
||||
color: '#ffffff',
|
||||
fontSize: 11,
|
||||
},
|
||||
data: categories.map((month) => monthStatusMap.get(month)?.get(status.key) || 0),
|
||||
}))
|
||||
: [
|
||||
{
|
||||
type: 'bar',
|
||||
barWidth: '12%',
|
||||
itemStyle: {
|
||||
color: isDark ? '#334155' : '#E2E8F0',
|
||||
borderRadius: [10, 10, 0, 0],
|
||||
},
|
||||
data: categories.map(() => 0),
|
||||
},
|
||||
];
|
||||
|
||||
if (hasData) {
|
||||
series.push({
|
||||
name: '总数',
|
||||
type: 'bar',
|
||||
stack: 'month-total',
|
||||
silent: true,
|
||||
legendHoverLink: false,
|
||||
itemStyle: {
|
||||
color: 'rgba(0,0,0,0)',
|
||||
},
|
||||
tooltip: {
|
||||
show: false,
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
color: isDark ? '#cbd5e1' : '#475569',
|
||||
fontSize: 11,
|
||||
formatter: ({ dataIndex }) => (totals[dataIndex] > 0 ? `${totals[dataIndex]}` : ''),
|
||||
},
|
||||
data: categories.map(() => 0),
|
||||
z: 10,
|
||||
});
|
||||
}
|
||||
|
||||
barChartInstance.setOption({
|
||||
grid: {
|
||||
left: 12,
|
||||
right: 12,
|
||||
top: 52,
|
||||
bottom: 10,
|
||||
containLabel: true,
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
},
|
||||
backgroundColor: isDark ? 'rgba(20, 20, 20, 0.96)' : 'rgba(255, 255, 255, 0.96)',
|
||||
borderColor: isDark ? 'rgb(51 65 85)' : 'rgb(226 232 240)',
|
||||
borderWidth: 1,
|
||||
textStyle: {
|
||||
color: isDark ? '#e2e8f0' : '#334155',
|
||||
},
|
||||
formatter: (params) => {
|
||||
const dataIndex = params[0]?.dataIndex || 0;
|
||||
if (!hasData) return '';
|
||||
const lines = params
|
||||
.filter((item) => item.seriesName !== '总数' && Number(item.value) > 0)
|
||||
.map((item) => `${item.marker}${item.seriesName}:${item.value}项`);
|
||||
lines.push(`总数:${totals[dataIndex]}项`);
|
||||
return `${categories[dataIndex]}<br/>${lines.join('<br/>')}`;
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
top: 6,
|
||||
left: 'center',
|
||||
itemGap: 16,
|
||||
data: statusItems.map((item) => item.label),
|
||||
textStyle: {
|
||||
color: isDark ? '#e2e8f0' : '#475569',
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: categories,
|
||||
boundaryGap: ['2%', '2%'],
|
||||
axisTick: {
|
||||
alignWithLabel: true,
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: isDark ? '#475569' : '#cbd5e1',
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
color: isDark ? '#cbd5e1' : '#64748b',
|
||||
interval: 0,
|
||||
margin: 8,
|
||||
rotate: 30,
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
minInterval: 1,
|
||||
name: '数量',
|
||||
nameTextStyle: {
|
||||
color: isDark ? '#94a3b8' : '#64748b',
|
||||
padding: [0, 0, 2, 0],
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: isDark ? 'rgba(71, 85, 105, 0.35)' : 'rgba(203, 213, 225, 0.55)',
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
color: isDark ? '#94a3b8' : '#64748b',
|
||||
},
|
||||
},
|
||||
series,
|
||||
});
|
||||
}
|
||||
|
||||
function renderCharts() {
|
||||
renderPieChart();
|
||||
renderBarChart();
|
||||
}
|
||||
|
||||
function resizeCharts() {
|
||||
pieChartInstance?.resize();
|
||||
barChartInstance?.resize();
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await Promise.all([getDict(), getList()]);
|
||||
await nextTick();
|
||||
renderCharts();
|
||||
|
||||
if (contractCardRef.value) {
|
||||
resizeObserver = new ResizeObserver(() => {
|
||||
resizeCharts();
|
||||
});
|
||||
resizeObserver.observe(contractCardRef.value);
|
||||
}
|
||||
|
||||
window.addEventListener('resize', resizeCharts);
|
||||
|
||||
themeObserver = new MutationObserver(() => {
|
||||
nextTick(() => {
|
||||
renderCharts();
|
||||
});
|
||||
});
|
||||
themeObserver.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['data-theme'],
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
resizeObserver?.disconnect();
|
||||
themeObserver?.disconnect();
|
||||
window.removeEventListener('resize', resizeCharts);
|
||||
pieChartInstance?.dispose();
|
||||
barChartInstance?.dispose();
|
||||
pieChartInstance = null;
|
||||
barChartInstance = null;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@workbench-dark-panel-bg: rgb(20, 20, 20);
|
||||
@workbench-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.contract-info-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
|
||||
.card-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 20px;
|
||||
color: rgb(51 65 85);
|
||||
border-bottom: 1px solid rgb(226 232 240);
|
||||
background: transparent;
|
||||
|
||||
&__more {
|
||||
padding: 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-content {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.contract-overview {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(220px, 0.9fr) minmax(0, 1.6fr);
|
||||
gap: 12px;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.task-chart-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
background: rgb(255, 255, 255);
|
||||
box-shadow: 0 8px 24px rgb(148 163 184 / 14%);
|
||||
}
|
||||
|
||||
.task-chart {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .contract-info-card {
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
border-bottom-color: rgb(51 65 85);
|
||||
|
||||
&__more:deep(.el-button) {
|
||||
color: rgb(147 197 253);
|
||||
}
|
||||
}
|
||||
|
||||
.task-chart-panel {
|
||||
background: @workbench-dark-panel-bg;
|
||||
box-shadow: @workbench-dark-shadow;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.contract-info-card {
|
||||
.contract-overview {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.contract-info-card {
|
||||
.card-content {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.task-chart-panel {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.task-chart {
|
||||
min-height: 220px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -331,6 +331,10 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@workbench-dark-panel-bg: rgb(20, 20, 20);
|
||||
@workbench-dark-solid-bg: rgb(20, 20, 20);
|
||||
@workbench-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.note-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -508,14 +512,14 @@
|
||||
|
||||
.metric-item,
|
||||
.note-chart-panel {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @workbench-dark-panel-bg;
|
||||
box-shadow: @workbench-dark-shadow;
|
||||
}
|
||||
|
||||
.metric-item {
|
||||
&__pane {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @workbench-dark-panel-bg;
|
||||
box-shadow: @workbench-dark-shadow;
|
||||
}
|
||||
|
||||
&__extra,
|
||||
@@ -525,12 +529,12 @@
|
||||
|
||||
&__label {
|
||||
border-color: rgb(51 65 85);
|
||||
background: rgb(20, 20, 20);
|
||||
background: @workbench-dark-solid-bg;
|
||||
}
|
||||
|
||||
&__label--active {
|
||||
border-color: rgb(59 130 246 / 40%);
|
||||
background: rgb(37 99 235 / 14%) !important;
|
||||
background: @workbench-dark-solid-bg !important;
|
||||
color: rgb(191 219 254) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,612 @@
|
||||
<template>
|
||||
<div ref="projectTaskCardRef" class="project-task-card">
|
||||
<div class="card-title">
|
||||
<span>项目任务</span>
|
||||
<el-button class="card-title__more" link type="primary" @click="goMore">更多</el-button>
|
||||
</div>
|
||||
|
||||
<div class="card-content">
|
||||
<div class="project-task-overview">
|
||||
<div class="task-chart-panel task-chart-panel--pie">
|
||||
<div ref="pieChartRef" class="task-chart"></div>
|
||||
</div>
|
||||
|
||||
<div class="task-chart-panel task-chart-panel--bar">
|
||||
<div ref="barChartRef" class="task-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import * as echarts from 'echarts';
|
||||
import { MyProjectTask, myProjectTaskListAll } from '@jeesite/biz/api/biz/myProjectTask';
|
||||
import { DictData, dictDataListData } from '@jeesite/core/api/sys/dictData';
|
||||
import { useUserStore } from '@jeesite/core/store/modules/user';
|
||||
import { firstCurrentYear, formatToDate } from '@jeesite/core/utils/dateUtil';
|
||||
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
const userinfo = computed(() => userStore.getUserInfo);
|
||||
|
||||
const projectTaskCardRef = ref<HTMLElement>();
|
||||
const pieChartRef = ref<HTMLElement>();
|
||||
const barChartRef = ref<HTMLElement>();
|
||||
const sourceData = ref<MyProjectTask[]>([]);
|
||||
const statusDict = ref<DictData[]>([]);
|
||||
|
||||
const STATUS_COLORS = ['#3B82F6', '#10B981', '#F97316', '#EC4899', '#8B5CF6', '#06B6D4'];
|
||||
let pieChartInstance: echarts.ECharts | null = null;
|
||||
let barChartInstance: echarts.ECharts | null = null;
|
||||
let resizeObserver: ResizeObserver | null = null;
|
||||
let themeObserver: MutationObserver | null = null;
|
||||
|
||||
function goMore() {
|
||||
router.push('/biz/myProjectTask/list');
|
||||
}
|
||||
|
||||
const pieChartData = computed(() => {
|
||||
if (!statusDict.value.length) {
|
||||
const fallbackMap = new Map<string, number>();
|
||||
sourceData.value.forEach((item) => {
|
||||
const label = item.taskStatus || '未设置';
|
||||
fallbackMap.set(label, (fallbackMap.get(label) || 0) + 1);
|
||||
});
|
||||
return Array.from(fallbackMap.entries()).map(([name, value], index) => ({
|
||||
name,
|
||||
value,
|
||||
itemStyle: { color: STATUS_COLORS[index % STATUS_COLORS.length] },
|
||||
}));
|
||||
}
|
||||
|
||||
const countMap = new Map<string, number>();
|
||||
sourceData.value.forEach((item) => {
|
||||
const key = item.taskStatus || 'unknown';
|
||||
countMap.set(key, (countMap.get(key) || 0) + 1);
|
||||
});
|
||||
|
||||
return statusDict.value
|
||||
.map((item, index) => ({
|
||||
name: item.dictLabelRaw,
|
||||
value: countMap.get(item.dictValue || '') || 0,
|
||||
itemStyle: { color: STATUS_COLORS[index % STATUS_COLORS.length] },
|
||||
}))
|
||||
.filter((item) => item.value > 0);
|
||||
});
|
||||
|
||||
const barChartData = computed(() => {
|
||||
const statusItems = statusDict.value.length
|
||||
? statusDict.value.map((item, index) => ({
|
||||
key: item.dictValue,
|
||||
label: item.dictLabelRaw,
|
||||
color: STATUS_COLORS[index % STATUS_COLORS.length],
|
||||
}))
|
||||
: [];
|
||||
|
||||
const monthStatusMap = new Map<string, Map<string, number>>();
|
||||
const monthOrderMap = new Map<string, number>();
|
||||
|
||||
sourceData.value.forEach((item) => {
|
||||
if (!item.createTime) return;
|
||||
const date = new Date(item.createTime);
|
||||
if (Number.isNaN(date.getTime())) return;
|
||||
const monthLabel = `${date.getMonth() + 1}月`;
|
||||
monthOrderMap.set(monthLabel, date.getMonth() + 1);
|
||||
const statusKey = item.taskStatus || 'unknown';
|
||||
if (!monthStatusMap.has(monthLabel)) {
|
||||
monthStatusMap.set(monthLabel, new Map<string, number>());
|
||||
}
|
||||
const monthMap = monthStatusMap.get(monthLabel)!;
|
||||
monthMap.set(statusKey, (monthMap.get(statusKey) || 0) + 1);
|
||||
});
|
||||
|
||||
const months = Array.from(monthStatusMap.keys()).sort((a, b) => {
|
||||
return (monthOrderMap.get(a) || 0) - (monthOrderMap.get(b) || 0);
|
||||
});
|
||||
|
||||
const totalByMonth = months.map((month) => {
|
||||
const monthMap = monthStatusMap.get(month);
|
||||
return Array.from(monthMap?.values() || []).reduce((sum, count) => sum + count, 0);
|
||||
});
|
||||
|
||||
const fallbackStatusMap = new Map<string, number>();
|
||||
sourceData.value.forEach((item) => {
|
||||
if (!statusDict.value.length) {
|
||||
const key = item.taskStatus || '未设置';
|
||||
fallbackStatusMap.set(key, (fallbackStatusMap.get(key) || 0) + 1);
|
||||
}
|
||||
});
|
||||
|
||||
const fallbackSeries = Array.from(fallbackStatusMap.keys()).map((key, index) => ({
|
||||
key,
|
||||
label: key,
|
||||
color: STATUS_COLORS[index % STATUS_COLORS.length],
|
||||
}));
|
||||
|
||||
return {
|
||||
months,
|
||||
totals: totalByMonth,
|
||||
statusItems: statusItems.length ? statusItems : fallbackSeries,
|
||||
monthStatusMap,
|
||||
};
|
||||
});
|
||||
|
||||
async function getDict() {
|
||||
try {
|
||||
statusDict.value = await dictDataListData({ dictType: 'task_status' });
|
||||
} catch (error) {
|
||||
statusDict.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
async function getList() {
|
||||
try {
|
||||
const reqParams = {
|
||||
createTime_gte: firstCurrentYear(),
|
||||
createUser: userinfo.value.loginCode,
|
||||
};
|
||||
const res = await myProjectTaskListAll(reqParams);
|
||||
sourceData.value = res || [];
|
||||
} catch (error) {
|
||||
sourceData.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
function renderPieChart() {
|
||||
if (!pieChartRef.value) return;
|
||||
if (!pieChartInstance) {
|
||||
pieChartInstance = echarts.init(pieChartRef.value);
|
||||
}
|
||||
|
||||
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
|
||||
const total = pieChartData.value.reduce((sum, item) => sum + Number(item.value || 0), 0);
|
||||
const data = total
|
||||
? pieChartData.value
|
||||
: statusDict.value.map((item, index) => ({
|
||||
name: item.dictLabelRaw,
|
||||
value: 0,
|
||||
itemStyle: { color: STATUS_COLORS[index % STATUS_COLORS.length] },
|
||||
}));
|
||||
const legendData = statusDict.value.length
|
||||
? statusDict.value.map((item) => item.dictLabelRaw)
|
||||
: pieChartData.value.map((item) => item.name);
|
||||
const series: echarts.SeriesOption[] = [];
|
||||
|
||||
if (!total) {
|
||||
series.push({
|
||||
name: '空态环',
|
||||
type: 'pie',
|
||||
radius: ['46%', '72%'],
|
||||
center: ['50%', '44%'],
|
||||
silent: true,
|
||||
legendHoverLink: false,
|
||||
tooltip: {
|
||||
show: false,
|
||||
},
|
||||
label: {
|
||||
show: false,
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
itemStyle: {
|
||||
color: isDark ? 'rgba(148, 163, 184, 0.18)' : 'rgba(203, 213, 225, 0.55)',
|
||||
borderRadius: 10,
|
||||
borderColor: isDark ? '#141414' : '#ffffff',
|
||||
borderWidth: 3,
|
||||
},
|
||||
data: [{ name: 'empty-ring', value: 1 }],
|
||||
});
|
||||
}
|
||||
|
||||
series.push({
|
||||
name: '任务状态',
|
||||
type: 'pie',
|
||||
radius: total ? ['46%', '72%'] : [0, 0],
|
||||
center: ['50%', '44%'],
|
||||
avoidLabelOverlap: true,
|
||||
minAngle: total ? 4 : 0,
|
||||
itemStyle: {
|
||||
borderRadius: 10,
|
||||
borderColor: isDark ? '#141414' : '#ffffff',
|
||||
borderWidth: 3,
|
||||
},
|
||||
label: {
|
||||
show: total,
|
||||
formatter: ({ name, value, percent }) => (total ? `${name}\n${value}项 / ${percent}%` : ''),
|
||||
color: isDark ? '#e2e8f0' : '#334155',
|
||||
fontSize: 12,
|
||||
},
|
||||
emphasis: {
|
||||
scale: true,
|
||||
scaleSize: 6,
|
||||
},
|
||||
data,
|
||||
silent: !total,
|
||||
labelLine: {
|
||||
show: total,
|
||||
},
|
||||
});
|
||||
|
||||
pieChartInstance.setOption({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
backgroundColor: isDark ? 'rgba(20, 20, 20, 0.96)' : 'rgba(255, 255, 255, 0.96)',
|
||||
borderColor: isDark ? 'rgb(51 65 85)' : 'rgb(226 232 240)',
|
||||
borderWidth: 1,
|
||||
textStyle: {
|
||||
color: isDark ? '#e2e8f0' : '#334155',
|
||||
},
|
||||
formatter: ({ name, value, percent }) => {
|
||||
if (!total) return `${name}<br/>数量:0`;
|
||||
return `${name}<br/>数量:${value}<br/>占比:${percent}%`;
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
show: legendData.length > 0,
|
||||
bottom: 4,
|
||||
left: 'center',
|
||||
itemWidth: 10,
|
||||
itemHeight: 10,
|
||||
data: legendData,
|
||||
textStyle: {
|
||||
color: isDark ? '#cbd5e1' : '#475569',
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
series,
|
||||
graphic: total
|
||||
? [
|
||||
{
|
||||
type: 'text',
|
||||
left: 'center',
|
||||
top: '34%',
|
||||
style: {
|
||||
text: '任务总数',
|
||||
fill: isDark ? '#94a3b8' : '#64748b',
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
left: 'center',
|
||||
top: '41%',
|
||||
style: {
|
||||
text: `${total}`,
|
||||
fill: isDark ? '#f8fafc' : '#0f172a',
|
||||
fontSize: 24,
|
||||
fontWeight: 700,
|
||||
},
|
||||
},
|
||||
]
|
||||
: [],
|
||||
});
|
||||
}
|
||||
|
||||
function renderBarChart() {
|
||||
if (!barChartRef.value) return;
|
||||
if (!barChartInstance) {
|
||||
barChartInstance = echarts.init(barChartRef.value);
|
||||
}
|
||||
|
||||
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
|
||||
const { months, totals, statusItems, monthStatusMap } = barChartData.value;
|
||||
const hasData = totals.some((item) => item > 0);
|
||||
const categories = months.length ? months : [];
|
||||
const series = statusItems.length
|
||||
? statusItems.map((status) => ({
|
||||
name: status.label,
|
||||
type: 'bar',
|
||||
stack: 'month-total',
|
||||
barWidth: '12%',
|
||||
itemStyle: {
|
||||
color: status.color,
|
||||
borderRadius: 0,
|
||||
},
|
||||
emphasis: {
|
||||
focus: 'series',
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'inside',
|
||||
formatter: ({ value }) => (Number(value) > 0 ? `${value}` : ''),
|
||||
color: '#ffffff',
|
||||
fontSize: 11,
|
||||
},
|
||||
data: categories.map((month) => monthStatusMap.get(month)?.get(status.key) || 0),
|
||||
}))
|
||||
: [
|
||||
{
|
||||
type: 'bar',
|
||||
barWidth: '12%',
|
||||
itemStyle: {
|
||||
color: isDark ? '#334155' : '#E2E8F0',
|
||||
borderRadius: [10, 10, 0, 0],
|
||||
},
|
||||
data: categories.map(() => 0),
|
||||
},
|
||||
];
|
||||
|
||||
if (hasData) {
|
||||
series.push({
|
||||
name: '总数',
|
||||
type: 'bar',
|
||||
stack: 'month-total',
|
||||
silent: true,
|
||||
legendHoverLink: false,
|
||||
itemStyle: {
|
||||
color: 'rgba(0,0,0,0)',
|
||||
},
|
||||
tooltip: {
|
||||
show: false,
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
color: isDark ? '#cbd5e1' : '#475569',
|
||||
fontSize: 11,
|
||||
formatter: ({ dataIndex }) => (totals[dataIndex] > 0 ? `${totals[dataIndex]}` : ''),
|
||||
},
|
||||
data: categories.map(() => 0),
|
||||
z: 10,
|
||||
});
|
||||
}
|
||||
|
||||
barChartInstance.setOption({
|
||||
grid: {
|
||||
left: 12,
|
||||
right: 12,
|
||||
top: 52,
|
||||
bottom: 10,
|
||||
containLabel: true,
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
},
|
||||
backgroundColor: isDark ? 'rgba(20, 20, 20, 0.96)' : 'rgba(255, 255, 255, 0.96)',
|
||||
borderColor: isDark ? 'rgb(51 65 85)' : 'rgb(226 232 240)',
|
||||
borderWidth: 1,
|
||||
textStyle: {
|
||||
color: isDark ? '#e2e8f0' : '#334155',
|
||||
},
|
||||
formatter: (params) => {
|
||||
const dataIndex = params[0]?.dataIndex || 0;
|
||||
if (!hasData) return '';
|
||||
const lines = params
|
||||
.filter((item) => item.seriesName !== '总数' && Number(item.value) > 0)
|
||||
.map((item) => `${item.marker}${item.seriesName}:${item.value}项`);
|
||||
lines.push(`总数:${totals[dataIndex]}项`);
|
||||
return `${categories[dataIndex]}<br/>${lines.join('<br/>')}`;
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
top: 6,
|
||||
left: 'center',
|
||||
itemGap: 16,
|
||||
data: statusItems.map((item) => item.label),
|
||||
textStyle: {
|
||||
color: isDark ? '#e2e8f0' : '#475569',
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: categories,
|
||||
boundaryGap: ['2%', '2%'],
|
||||
axisTick: {
|
||||
alignWithLabel: true,
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: isDark ? '#475569' : '#cbd5e1',
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
color: isDark ? '#cbd5e1' : '#64748b',
|
||||
interval: 0,
|
||||
margin: 8,
|
||||
rotate: 30,
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: '数量',
|
||||
nameTextStyle: {
|
||||
color: isDark ? '#94a3b8' : '#64748b',
|
||||
padding: [0, 0, 2, 0],
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: isDark ? 'rgba(71, 85, 105, 0.35)' : 'rgba(203, 213, 225, 0.55)',
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
color: isDark ? '#94a3b8' : '#64748b',
|
||||
},
|
||||
},
|
||||
series,
|
||||
});
|
||||
}
|
||||
|
||||
function renderCharts() {
|
||||
renderPieChart();
|
||||
renderBarChart();
|
||||
}
|
||||
|
||||
function resizeCharts() {
|
||||
pieChartInstance?.resize();
|
||||
barChartInstance?.resize();
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await Promise.all([getDict(), getList()]);
|
||||
await nextTick();
|
||||
renderCharts();
|
||||
|
||||
if (projectTaskCardRef.value) {
|
||||
resizeObserver = new ResizeObserver(() => {
|
||||
resizeCharts();
|
||||
});
|
||||
resizeObserver.observe(projectTaskCardRef.value);
|
||||
}
|
||||
|
||||
window.addEventListener('resize', resizeCharts);
|
||||
|
||||
themeObserver = new MutationObserver(() => {
|
||||
nextTick(() => {
|
||||
renderCharts();
|
||||
});
|
||||
});
|
||||
themeObserver.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['data-theme'],
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
resizeObserver?.disconnect();
|
||||
themeObserver?.disconnect();
|
||||
window.removeEventListener('resize', resizeCharts);
|
||||
pieChartInstance?.dispose();
|
||||
barChartInstance?.dispose();
|
||||
pieChartInstance = null;
|
||||
barChartInstance = null;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@workbench-dark-panel-bg: rgb(20, 20, 20);
|
||||
@workbench-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.project-task-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
|
||||
.card-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 20px;
|
||||
color: rgb(51 65 85);
|
||||
border-bottom: 1px solid rgb(226 232 240);
|
||||
background: transparent;
|
||||
|
||||
&__more {
|
||||
padding: 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-content {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
padding: 16px;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.project-task-overview {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(220px, 0.9fr) minmax(0, 1.6fr);
|
||||
gap: 12px;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.task-chart-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
padding: 12px;
|
||||
border-radius: 12px;
|
||||
background: rgb(255, 255, 255);
|
||||
box-shadow: 0 8px 24px rgb(148 163 184 / 14%);
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
color: rgb(51 65 85);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.panel-subtitle {
|
||||
color: rgb(100 116 139);
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.task-chart {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .project-task-card {
|
||||
.card-title {
|
||||
color: rgb(203 213 225);
|
||||
border-bottom-color: rgb(51 65 85);
|
||||
|
||||
&__more:deep(.el-button) {
|
||||
color: rgb(147 197 253);
|
||||
}
|
||||
}
|
||||
|
||||
.task-chart-panel {
|
||||
background: @workbench-dark-panel-bg;
|
||||
box-shadow: @workbench-dark-shadow;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
color: rgb(226 232 240);
|
||||
}
|
||||
|
||||
.panel-subtitle {
|
||||
color: rgb(148 163 184);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.project-task-card {
|
||||
.project-task-overview {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.project-task-card {
|
||||
.card-content {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.task-chart-panel {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.task-chart {
|
||||
min-height: 220px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -314,6 +314,10 @@
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
@workbench-dark-panel-bg: rgb(20, 20, 20);
|
||||
@workbench-dark-solid-bg: rgb(20, 20, 20);
|
||||
@workbench-dark-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
|
||||
.schedule-card {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@@ -700,14 +704,14 @@
|
||||
|
||||
.summary-item,
|
||||
.schedule-panel {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @workbench-dark-panel-bg;
|
||||
box-shadow: @workbench-dark-shadow;
|
||||
}
|
||||
|
||||
.summary-item {
|
||||
&__pane {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @workbench-dark-panel-bg;
|
||||
box-shadow: @workbench-dark-shadow;
|
||||
}
|
||||
|
||||
&__extra,
|
||||
@@ -717,7 +721,7 @@
|
||||
|
||||
&__label {
|
||||
border-color: rgb(51 65 85);
|
||||
background: rgb(20, 20, 20);
|
||||
background: @workbench-dark-solid-bg;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -734,12 +738,12 @@
|
||||
|
||||
.panel-tag,
|
||||
.timeline-scroll {
|
||||
background: linear-gradient(180deg, rgb(20, 20, 20) 0%, rgb(28 28 28) 100%);
|
||||
box-shadow: 0 10px 24px rgb(0 0 0 / 24%);
|
||||
background: @workbench-dark-panel-bg;
|
||||
box-shadow: @workbench-dark-shadow;
|
||||
}
|
||||
|
||||
.timeline-row__hint {
|
||||
background: rgb(30 41 59 / 75%);
|
||||
background: @workbench-dark-solid-bg;
|
||||
}
|
||||
|
||||
.timeline-row__hint-title {
|
||||
@@ -756,7 +760,7 @@
|
||||
|
||||
.timeline-event {
|
||||
border-color: rgb(51 65 85);
|
||||
background: rgb(30 41 59 / 55%);
|
||||
background: @workbench-dark-solid-bg;
|
||||
color: rgb(226 232 240);
|
||||
|
||||
&:hover {
|
||||
@@ -778,7 +782,7 @@
|
||||
}
|
||||
|
||||
&__label {
|
||||
background: rgb(69 10 10);
|
||||
background: @workbench-dark-solid-bg;
|
||||
color: rgb(254 202 202);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<PageWrapper :contentFullHeight="true">
|
||||
<PageWrapper :contentFullHeight="true" :dense="true" title="false" contentClass="workbench-page-wrapper">
|
||||
<template #headerContent>
|
||||
<WorkbenchHeader />
|
||||
</template>
|
||||
@@ -14,8 +14,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="workbench-row">
|
||||
<div class="workbench-col">下左</div>
|
||||
<div class="workbench-col">下右</div>
|
||||
<div class="workbench-col">
|
||||
<ProjectTask />
|
||||
</div>
|
||||
<div class="workbench-col">
|
||||
<ContractInfo />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -26,6 +30,8 @@
|
||||
import { PageWrapper } from '@jeesite/core/components/Page';
|
||||
import WorkbenchHeader from './components/WorkbenchHeader.vue';
|
||||
import NoteInfo from './components/NoteInfo.vue';
|
||||
import ProjectTask from './components/ProjectTask.vue';
|
||||
import ContractInfo from './components/ContractInfo.vue';
|
||||
import ScheduleInfo from './components/ScheduleInfo.vue';
|
||||
|
||||
const loading = ref(true);
|
||||
@@ -36,44 +42,64 @@
|
||||
|
||||
<style lang="less">
|
||||
@dark-bg: #141414;
|
||||
@desktop-page-gap: 12px;
|
||||
@desktop-page-padding: 0;
|
||||
@desktop-card-radius: 10px;
|
||||
@desktop-card-border: 1px solid rgb(226 232 240);
|
||||
@desktop-card-shadow: 0 1px 3px rgb(15 23 42 / 0.06);
|
||||
@desktop-dark-border: rgb(51 65 85);
|
||||
|
||||
.workbench-page-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
padding: 0 !important;
|
||||
overflow: hidden !important;
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
.jeesite-workbench {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
margin: 0;
|
||||
background: rgb(255, 255, 255);
|
||||
border-radius: 10px;
|
||||
border-radius: @desktop-card-radius;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-layout {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
gap: @desktop-page-gap;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
padding: @desktop-page-padding;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
border-radius: 10px;
|
||||
border-radius: @desktop-card-radius;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-row {
|
||||
display: flex;
|
||||
flex: 1 1 0;
|
||||
gap: 8px;
|
||||
gap: @desktop-page-gap;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.jeesite-workbench .workbench-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgb(226 232 240);
|
||||
border-radius: @desktop-card-radius;
|
||||
border: @desktop-card-border;
|
||||
background: rgb(255, 255, 255);
|
||||
box-shadow: 0 1px 3px rgb(15 23 42 / 0.06);
|
||||
box-shadow: @desktop-card-shadow;
|
||||
color: rgb(71 85 105);
|
||||
font-size: 16px;
|
||||
overflow: hidden;
|
||||
@@ -91,7 +117,7 @@
|
||||
}
|
||||
|
||||
html[data-theme='dark'] .jeesite-workbench .workbench-col {
|
||||
border-color: rgb(51 65 85);
|
||||
border-color: @desktop-dark-border;
|
||||
background: @dark-bg !important;
|
||||
color: rgb(226 232 240);
|
||||
box-shadow: none;
|
||||
|
||||
@@ -19,4 +19,12 @@ export function formatToDate(date: dayjs.ConfigType | undefined = undefined, for
|
||||
return dayjs(date).format(format);
|
||||
}
|
||||
|
||||
export function firstCurrentYear(format = DATE_FORMAT): string {
|
||||
return dayjs().startOf('year').format(format);
|
||||
}
|
||||
|
||||
export function firstCurrentMonth(format = DATE_FORMAT): string {
|
||||
return dayjs().startOf('month').format(format);
|
||||
}
|
||||
|
||||
export const dateUtil = dayjs;
|
||||
|
||||
Reference in New Issue
Block a user