Commit 718c52c3faff473133d57d0e70922ac587e720ee

Authored by sanmu
1 parent eea414e0

feat: update

Showing 77 changed files with 3393 additions and 365 deletions

Too many changes to show.

To preserve performance only 77 of 83 files are displayed.

1 1 # spa-title
2   -VITE_GLOB_APP_TITLE = Vben Admin
  2 +VITE_GLOB_APP_TITLE = 订单管理系统
  3 +VITE_SANMU = sanmu123
  4 +VITE_IS_DEV = true
... ...
.pnpm-debug.log 0 → 100644
  1 +{
  2 + "0 error pnpm": {
  3 + "code": "ERR_PNPM_UNSUPPORTED_ENGINE",
  4 + "packageId": "/Users/sanmu/Documents/teach/vue-vben-admin",
  5 + "wanted": {
  6 + "pnpm": ">=8.1.0"
  7 + },
  8 + "current": {
  9 + "node": "v18.14.1",
  10 + "pnpm": "7.4.1"
  11 + },
  12 + "err": {
  13 + "name": "pnpm",
  14 + "message": "Unsupported engine for /Users/sanmu/Documents/teach/vue-vben-admin: wanted: {\"pnpm\":\">=8.1.0\"} (current: {\"node\":\"v18.14.1\",\"pnpm\":\"7.4.1\"})",
  15 + "code": "ERR_PNPM_UNSUPPORTED_ENGINE",
  16 + "stack": "pnpm: Unsupported engine for /Users/sanmu/Documents/teach/vue-vben-admin: wanted: {\"pnpm\":\">=8.1.0\"} (current: {\"node\":\"v18.14.1\",\"pnpm\":\"7.4.1\"})\n at checkEngine (/Users/zhusen/.nvm/versions/node/v16.13.0/lib/node_modules/pnpm/dist/pnpm.cjs:43094:16)\n at checkPackage (/Users/zhusen/.nvm/versions/node/v16.13.0/lib/node_modules/pnpm/dist/pnpm.cjs:43677:74)\n at packageIsInstallable (/Users/zhusen/.nvm/versions/node/v16.13.0/lib/node_modules/pnpm/dist/pnpm.cjs:43700:61)\n at exports2.default (/Users/zhusen/.nvm/versions/node/v16.13.0/lib/node_modules/pnpm/dist/pnpm.cjs:49525:46)\n at async run (/Users/zhusen/.nvm/versions/node/v16.13.0/lib/node_modules/pnpm/dist/pnpm.cjs:192508:29)\n at async runPnpm (/Users/zhusen/.nvm/versions/node/v16.13.0/lib/node_modules/pnpm/dist/pnpm.cjs:192771:5)\n at async /Users/zhusen/.nvm/versions/node/v16.13.0/lib/node_modules/pnpm/dist/pnpm.cjs:192763:7"
  17 + }
  18 + }
  19 +}
0 20 \ No newline at end of file
... ...
mock/demo/table-demo.ts
... ... @@ -37,6 +37,14 @@ const demoList = (() => {
37 37 time: `@time('HH:mm')`,
38 38 'no|100000-10000000': 100000,
39 39 'status|1': ['normal', 'enable', 'disable'],
  40 + no1: '字段内容',
  41 + no2: '字段内容',
  42 + no3: '字段内容',
  43 + no4: '字段内容',
  44 + no5: '字段内容',
  45 + no6: '字段内容',
  46 + no7: '字段内容',
  47 + no8: '字段内容',
40 48 });
41 49 }
42 50 return result;
... ...
mock/sys/user.ts
... ... @@ -11,7 +11,7 @@ export function createFakeUserList() {
11 11 desc: 'manager',
12 12 password: '123456',
13 13 token: 'fakeToken1',
14   - homePath: '/dashboard/analysis',
  14 + homePath: '/home',
15 15 roles: [
16 16 {
17 17 roleName: 'Super Admin',
... ...
package.json
... ... @@ -17,7 +17,7 @@
17 17 },
18 18 "scripts": {
19 19 "bootstrap": "pnpm install",
20   - "build": "cross-env NODE_ENV=production NODE_OPTIONS=--max-old-space-size=8192 pnpm vite build",
  20 + "build": "cross-env NODE_ENV=development NODE_OPTIONS=--max-old-space-size=8192 pnpm vite build",
21 21 "build:analyze": "cross-env NODE_OPTIONS=--max-old-space-size=8192 pnpm vite build --mode analyze",
22 22 "build:docker": "vite build --mode docker",
23 23 "build:no-cache": "pnpm clean:cache && npm run build",
... ... @@ -151,4 +151,4 @@
151 151 "node": ">=16.15.1",
152 152 "pnpm": ">=8.1.0"
153 153 }
154 154 -}
  155 +}
155 156 \ No newline at end of file
... ...
src/api/demo/system.ts
... ... @@ -13,17 +13,21 @@ import {
13 13 import { defHttp } from '/@/utils/http/axios';
14 14  
15 15 enum Api {
16   - AccountList = '/system/getAccountList',
  16 + AccountList = '/order/erp/users/list_by_page',
17 17 IsAccountExist = '/system/accountExist',
18 18 DeptList = '/system/getDeptList',
19 19 setRoleStatus = '/system/setRoleStatus',
20 20 MenuList = '/system/getMenuList',
21   - RolePageList = '/system/getRoleListByPage',
  21 + RolePageList = '/order/erp/roles/list_by_page',
22 22 GetAllRoleList = '/system/getAllRoleList',
23 23 }
24 24  
25   -export const getAccountList = (params: AccountParams) =>
26   - defHttp.get<AccountListGetResultModel>({ url: Api.AccountList, params });
  25 +export const getAccountList = async (params: AccountParams) => {
  26 + const res = await defHttp.post<AccountListGetResultModel>({ url: Api.AccountList, params });
  27 + return new Promise((resolve) => {
  28 + resolve(res.records);
  29 + });
  30 +};
27 31  
28 32 export const getDeptList = (params?: DeptListItem) =>
29 33 defHttp.get<DeptListGetResultModel>({ url: Api.DeptList, params });
... ... @@ -31,8 +35,12 @@ export const getDeptList = (params?: DeptListItem) =&gt;
31 35 export const getMenuList = (params?: MenuParams) =>
32 36 defHttp.get<MenuListGetResultModel>({ url: Api.MenuList, params });
33 37  
34   -export const getRoleListByPage = (params?: RolePageParams) =>
35   - defHttp.get<RolePageListGetResultModel>({ url: Api.RolePageList, params });
  38 +export const getRoleListByPage = async (params?: RolePageParams) => {
  39 + const res = await defHttp.post<RolePageListGetResultModel>({ url: Api.RolePageList, params });
  40 + return new Promise((resolve) => {
  41 + resolve(res.records);
  42 + });
  43 +};
36 44  
37 45 export const getAllRoleList = (params?: RoleParams) =>
38 46 defHttp.get<RoleListGetResultModel>({ url: Api.GetAllRoleList, params });
... ...
src/api/demo/table.ts
1 1 import { defHttp } from '/@/utils/http/axios';
2 2 import { DemoParams, DemoListGetResultModel } from './model/tableModel';
  3 +import { find } from 'lodash-es';
  4 +import { FIELDS_BASE_INFO } from '/@/views/project/order/tableData';
3 5  
4 6 enum Api {
5 7 DEMO_LIST = '/table/getDemoList',
  8 + ORDER = '/order/erp/order/list_by_page',
  9 + DICT_INIT = '/order/erp/dictionary/get_all',
  10 + APPROVE = '/order/erp/audit/list_by_page',
  11 + CHECK = '/order/erp/audit/do_audit',
6 12 }
7 13  
8 14 /**
9 15 * @description: Get sample list value
10 16 */
11 17  
12   -export const demoListApi = (params: DemoParams) =>
13   - defHttp.get<DemoListGetResultModel>({
14   - url: Api.DEMO_LIST,
  18 +export const demoListApi = async (params: DemoParams) => {
  19 + const res = await defHttp.post<DemoListGetResultModel>({
  20 + url: Api.ORDER,
15 21 params,
16 22 headers: {
17 23 // @ts-ignore
18 24 ignoreCancelToken: true,
19 25 },
20 26 });
  27 + return new Promise((resolve) => {
  28 + resolve(res.records);
  29 + });
  30 +};
  31 +
  32 +export const demoApproveListApi = async (params: DemoParams) => {
  33 + const res = await defHttp.post<DemoListGetResultModel>({
  34 + url: Api.APPROVE,
  35 + params,
  36 + });
  37 +
  38 + res.records = res.records.map((item) => {
  39 + item.fields = [];
  40 + Object.entries(item.fieldInfos.baseFields).map(([key, value]) => {
  41 + if (value === 'UN_LOCKED') {
  42 + const obj = find(FIELDS_BASE_INFO, { field: key });
  43 + item.fields.push(obj?.label);
  44 + }
  45 + });
  46 + item.fields = item.fields.join(',');
  47 + return item;
  48 + });
  49 +
  50 + return new Promise((resolve) => {
  51 + resolve(res.records);
  52 + });
  53 +};
  54 +
  55 +export const demoApproveCheckApi = async (params: DemoParams) => {
  56 + const res = await defHttp.post<DemoListGetResultModel>({
  57 + url: Api.CHECK,
  58 + params,
  59 + headers: {
  60 + // @ts-ignore
  61 + ignoreCancelToken: true,
  62 + },
  63 + });
  64 + return new Promise((resolve) => {
  65 + resolve(res);
  66 + });
  67 +};
  68 +
  69 +export const getInitDictData = async () => {
  70 + const res = await defHttp.post({
  71 + url: Api.DICT_INIT,
  72 + params: {},
  73 + headers: {
  74 + // @ts-ignore
  75 + ignoreCancelToken: true,
  76 + },
  77 + });
  78 +
  79 + return res;
  80 +};
... ...
src/api/project/account.ts 0 → 100644
  1 +import { defHttp } from '/@/utils/http/axios';
  2 +
  3 +enum Api {
  4 + ROLE_LIST = '/order/erp/roles/all',
  5 + USER_LIST = '/order/erp/users/list_by_page',
  6 + USER_ADD = '/order/erp/roles/add',
  7 + USER_EDIT = '/order/erp/roles/edit',
  8 + USER_DELETE = '/order/erp/roles/delete',
  9 +}
  10 +
  11 +export const getRoleList = async (params: any) => {
  12 + return defHttp.post<any>({
  13 + url: Api.ROLE_LIST,
  14 + params,
  15 + });
  16 +};
  17 +
  18 +export const getUserList = async (params: any) => {
  19 + const res = await defHttp.post<any>({
  20 + url: Api.USER_LIST,
  21 + params,
  22 + });
  23 + return new Promise((resolve) => {
  24 + resolve(res.records);
  25 + });
  26 +};
  27 +
  28 +// export const getAccountList = async (params: AccountParams) => {
  29 +// const res = await defHttp.post<AccountListGetResultModel>({ url: Api.AccountList, params });
  30 +// return new Promise((resolve) => {
  31 +// resolve(res.records);
  32 +// });
  33 +// };
  34 +
  35 +export const userAdd = async (params: any) => {
  36 + return defHttp.post<any>({
  37 + url: Api.USER_ADD,
  38 + params,
  39 + });
  40 +};
  41 +
  42 +export const userEdit = async (params: any) => {
  43 + return defHttp.post<any>({
  44 + url: Api.USER_EDIT,
  45 + params,
  46 + });
  47 +};
  48 +
  49 +export const userDelete = async (params: any) => {
  50 + return defHttp.post<any>({
  51 + url: Api.USER_DELETE,
  52 + params,
  53 + });
  54 +};
... ...
src/api/project/approve.ts 0 → 100644
  1 +import { find, isEmpty } from 'lodash-es';
  2 +import { defHttp } from '/@/utils/http/axios';
  3 +import { FIELDS_BASE_INFO, FIELDS_PROFIT_INFO } from '/@/views/project/order/tableData';
  4 +
  5 +enum Api {
  6 + APPROVE = '/order/erp/audit/wait_audit_list',
  7 + APPROVE_ED = '/order/erp/audit/audit_list',
  8 + AUDIT = '/order/erp/audit/do_audit',
  9 +}
  10 +
  11 +export const approveAuditApi = async (params: any) =>
  12 + defHttp.post<any>(
  13 + {
  14 + url: Api.AUDIT,
  15 + params,
  16 + },
  17 + { message: '操作成功' },
  18 + );
  19 +
  20 +export const getWaitListApi = async (params: DemoParams) => {
  21 + const res = await defHttp.post({
  22 + url: Api.APPROVE,
  23 + params,
  24 + });
  25 +
  26 + console.log('%c [ ]-26', 'font-size:13px; background:pink; color:#bf2c9f;', 123);
  27 + res.records = res.records.map((item) => {
  28 + item.fields = [];
  29 + !isEmpty(item.fieldInfos.baseFields) &&
  30 + Object.entries(item.fieldInfos.baseFields).map(([key, value]) => {
  31 + if (value === 'UN_LOCKED') {
  32 + const obj = find(FIELDS_BASE_INFO, { field: key });
  33 + item.fields.push(obj?.label);
  34 + }
  35 + });
  36 + !isEmpty(item.fieldInfos.baseFields) &&
  37 + Object.entries(item.fieldInfos.profitAnalysisFields).map(([key, value]) => {
  38 + if (value === 'UN_LOCKED') {
  39 + const obj = find(FIELDS_PROFIT_INFO, { field: `profitAnalysisFields.${key}` });
  40 + item.fields.push(obj?.label);
  41 + }
  42 + });
  43 + item.fields = item.fields.join(',');
  44 + return item;
  45 + });
  46 + console.log(
  47 + '%c [ res.records ]-27',
  48 + 'font-size:13px; background:pink; color:#bf2c9f;',
  49 + res.records,
  50 + );
  51 +
  52 + return new Promise((resolve) => {
  53 + resolve(res.records);
  54 + });
  55 +};
  56 +
  57 +export const getApprovedListApi = async (params: any) => {
  58 + const res = await defHttp.post({
  59 + url: Api.APPROVE_ED,
  60 +
  61 + params,
  62 + });
  63 +
  64 + res.records = res.records.map((item) => {
  65 + item.fields = [];
  66 + Object.entries(item.fieldInfos.baseFields).map(([key, value]) => {
  67 + if (value === 'UN_LOCKED') {
  68 + const obj = find(FIELDS_BASE_INFO, { field: key });
  69 + item.fields.push(obj?.label);
  70 + }
  71 + });
  72 + item.fields = item.fields.join(',');
  73 + return item;
  74 + });
  75 +
  76 + return new Promise((resolve) => {
  77 + resolve(res.records);
  78 + });
  79 +};
... ...
src/api/project/global.ts 0 → 100644
  1 +import { defHttp } from '/@/utils/http/axios';
  2 +
  3 +enum Api {
  4 + DATA = '/order/erp/index/data',
  5 + CHART_DATA = '/order/erp/index/chartData',
  6 +}
  7 +
  8 +export const getApiData = async () => {
  9 + const res = await defHttp.get<any>({ url: Api.DATA });
  10 + return res;
  11 +};
  12 +
  13 +export const getChartData = async () => {
  14 + const res = await defHttp.get<any>({ url: Api.CHART_DATA });
  15 + return res;
  16 +};
... ...
src/api/project/order.ts 0 → 100644
  1 +import axios from 'axios';
  2 +import { defHttp } from '/@/utils/http/axios';
  3 +import { useUserStoreWithOut } from '/@/store/modules/user';
  4 +import { useOrderStoreWithOut } from '/@/store/modules/order';
  5 +
  6 +enum Api {
  7 + ORDER_CREATE = '/order/erp/order/add',
  8 + UPDATE = '/order/erp/order/edit',
  9 + ORDER = '/order/erp/order/list_by_page',
  10 + FIELD_AUTH = '/order/erp/order/field_unlock_apply',
  11 + EXPORT = '/order/erp/order/export',
  12 + UPLOAD = '/api/localStorage/upload',
  13 +
  14 + DICT_INIT = '/order/erp/dictionary/get_all',
  15 + DICT_ADD = '/order/erp/dictionary/add',
  16 + DICT_UPDATE = '/order/erp/dictionary/edit',
  17 + DICT_DELETE = '/order/erp/dictionary/delete',
  18 + DICT_LIST = '/order/erp/dictionary/list_by_page',
  19 +
  20 + ANALYSIS = '/order/erp/profit/analysis',
  21 +}
  22 +
  23 +export const orderCreate = async (data: any) => {
  24 + const res = await defHttp.post<any>({ url: Api.ORDER_CREATE, data }, { message: '保存成功' });
  25 + return res;
  26 +};
  27 +
  28 +export const orderUpdate = async (data: any) => {
  29 + const res = await defHttp.post<any>({ url: Api.UPDATE, data });
  30 + return res;
  31 +};
  32 +
  33 +export const orderAuth = (data: any) =>
  34 + defHttp.post<any>({ url: Api.FIELD_AUTH, data }, { message: '操作成功' });
  35 +
  36 +export const orderAnalysis = async (data: any) => {
  37 + const res = await defHttp.post<any>({ url: Api.ANALYSIS, data });
  38 + return res;
  39 +};
  40 +
  41 +export const orderExport = async (data: any = {}) => {
  42 + // const res = await defHttp.post<any>({ url: Api.EXPORT, data });
  43 + const userStore = useUserStoreWithOut();
  44 +
  45 + const token = userStore.getToken;
  46 +
  47 + axios({
  48 + url: '/basic-api' + Api.EXPORT,
  49 + method: 'post',
  50 + responseType: 'blob',
  51 + headers: { Authorization: `Bearer ${token}` },
  52 + data,
  53 + })
  54 + .then((response) => {
  55 + // 创建一个新的 Blob 对象,它包含了服务器响应的数据(即你的 Excel 文件)
  56 + const blob = new Blob([response.data]); // Excel 的 MIME 类型
  57 + const downloadUrl = window.URL.createObjectURL(blob);
  58 + const a = document.createElement('a');
  59 + a.href = downloadUrl;
  60 + a.download = '订单.xlsx'; // 你可以为文件命名
  61 + document.body.appendChild(a);
  62 + a.click(); // 模拟点击操作来下载文件
  63 + URL.revokeObjectURL(downloadUrl); // 释放掉 blob 对象所占用的内存
  64 + document.body.removeChild(a);
  65 + })
  66 + .catch((error) => {
  67 + // 处理错误
  68 + console.error('导出错误', error);
  69 + });
  70 +};
  71 +
  72 +export const getInitDictData = async () => {
  73 + const res = await defHttp.post({
  74 + url: Api.DICT_INIT,
  75 + });
  76 +
  77 + return res;
  78 +};
  79 +
  80 +export async function uploadImg(params, onUploadProgress: (progressEvent: ProgressEvent) => void) {
  81 + const res = await defHttp.uploadFile(
  82 + {
  83 + url: Api.UPLOAD,
  84 + onUploadProgress,
  85 + },
  86 + {
  87 + file: params.file,
  88 + data: { name: params.file.name },
  89 + },
  90 + );
  91 + return Promise.resolve({ data: { thumbUrl: res.data } });
  92 +}
  93 +
  94 +export const getOrderList = async (params: DemoParams) => {
  95 + const res = await defHttp.post<DemoListGetResultModel>({
  96 + url: Api.ORDER,
  97 + params,
  98 + headers: {
  99 + // @ts-ignore
  100 + ignoreCancelToken: true,
  101 + },
  102 + });
  103 + const orderStore = useOrderStoreWithOut();
  104 + orderStore.setTotal(res.total);
  105 + return new Promise((resolve) => {
  106 + resolve({
  107 + items: res.records,
  108 + total: res.total,
  109 + });
  110 + });
  111 +};
  112 +
  113 +export const dictCreate = async (data: any) => {
  114 + const res = await defHttp.post<any>({ url: Api.DICT_ADD, data }, { message: '保存成功' });
  115 + return res;
  116 +};
  117 +
  118 +export const dictUpdate = async (data: any) => {
  119 + const res = await defHttp.post<any>({ url: Api.DICT_UPDATE, data }, { message: '保存成功' });
  120 + return res;
  121 +};
  122 +
  123 +export const dictDelete = async (data: any) => {
  124 + const res = await defHttp.post<any>({ url: Api.DICT_DELETE, data }, { message: '保存成功' });
  125 + return res;
  126 +};
  127 +
  128 +export const dictList = async (data: any) => {
  129 + const res = await defHttp.post<any>({ url: Api.DICT_LIST, data: { ...data, pageSize: 1000 } });
  130 + return res;
  131 +};
... ...
src/api/sys/model/userModel.ts
... ... @@ -2,8 +2,10 @@
2 2 * @description: Login interface parameters
3 3 */
4 4 export interface LoginParams {
5   - username: string;
  5 + userName: string;
6 6 password: string;
  7 + imgCaptchaCode: string;
  8 + imgCaptchaUuid: string;
7 9 }
8 10  
9 11 export interface RoleInfo {
... ...
src/api/sys/user.ts
... ... @@ -4,7 +4,8 @@ import { LoginParams, LoginResultModel, GetUserInfoModel } from &#39;./model/userMod
4 4 import { ErrorMessageMode } from '/#/axios';
5 5  
6 6 enum Api {
7   - Login = '/login',
  7 + // Login = '/login',
  8 + Login = '/order/erp/auth/login_by_pwd',
8 9 Logout = '/logout',
9 10 GetUserInfo = '/getUserInfo',
10 11 GetPermCode = '/getPermCode',
... ... @@ -53,3 +54,7 @@ export function testRetry() {
53 54 },
54 55 );
55 56 }
  57 +
  58 +export function getImageCaptcha() {
  59 + return defHttp.post({ url: '/order/erp/captcha/get_img_captcha_code' });
  60 +}
... ...
src/components/FieldUpload/index.ts 0 → 100644
  1 +import { withInstall } from '/@/utils';
  2 +import fieldUpload from './src/FieldUpload.vue';
  3 +
  4 +const FieldUpload = withInstall(fieldUpload);
  5 +export default FieldUpload;
... ...
src/components/FieldUpload/src/FieldUpload.vue 0 → 100644
  1 +<template>
  2 + <Upload
  3 + v-model:file-list="fileList"
  4 + name="file"
  5 + list-type="picture-card"
  6 + class="avatar-uploader"
  7 + :show-upload-list="false"
  8 + action="/api/localStorage/upload"
  9 + accept=".jpg,.jpeg,.gif,.png,.webp"
  10 + :data="handleData"
  11 + >
  12 + <img v-if="imgUrl" :src="imgUrl" alt="avatar" width="100" height="100" />
  13 + <div v-else>
  14 + <loading-outlined v-if="loading" />
  15 + <plus-outlined v-else />
  16 + <div class="ant-upload-text">上传</div>
  17 + </div>
  18 + </Upload>
  19 +</template>
  20 +<script lang="ts" setup>
  21 + import { defineProps, ref } from 'vue';
  22 +
  23 + import { Upload, message } from 'ant-design-vue';
  24 + import { PlusOutlined, LoadingOutlined } from '@ant-design/icons-vue';
  25 + import type { UploadChangeParam, UploadProps } from 'ant-design-vue';
  26 +
  27 + const props = defineProps({
  28 + imgUrl: String, // 期望 'value' 是一个字符串。根据您的需求调整类型。
  29 + });
  30 + console.log('%c [ props ]-29', 'font-size:13px; background:pink; color:#bf2c9f;', props);
  31 +
  32 + function getBase64(img: Blob, callback: (base64Url: string) => void) {
  33 + const reader = new FileReader();
  34 + reader.addEventListener('load', () => callback(reader.result as string));
  35 + reader.readAsDataURL(img);
  36 + }
  37 + const handleData = (data) => {
  38 + console.log('%c [ data ]-32', 'font-size:13px; background:pink; color:#bf2c9f;', data);
  39 + return { name: data.name };
  40 + };
  41 +
  42 + const fileList = ref([]);
  43 + const loading = ref<boolean>(false);
  44 + const imageUrl = ref<string>('');
  45 +
  46 + const handleChange = (info: UploadChangeParam) => {
  47 + // if (info.file.status === 'uploading') {
  48 + // loading.value = true;
  49 + // return;
  50 + // }
  51 + // if (info.file.status === 'done') {
  52 + // // Get this url from response in real world.
  53 + // getBase64(info.file.originFileObj, (base64Url: string) => {
  54 + // imageUrl.value = base64Url;
  55 + // loading.value = false;
  56 + // });
  57 + // }
  58 + // if (info.file.status === 'error') {
  59 + // loading.value = false;
  60 + // message.error('upload error');
  61 + // }
  62 + };
  63 +
  64 + const beforeUpload = (file: UploadProps['fileList'][number]) => {
  65 + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
  66 + if (!isJpgOrPng) {
  67 + message.error('You can only upload JPG file!');
  68 + }
  69 + const isLt2M = file.size / 1024 / 1024 < 2;
  70 + if (!isLt2M) {
  71 + message.error('图片最大10MB!');
  72 + }
  73 + return isJpgOrPng && isLt2M;
  74 + };
  75 +</script>
  76 +<style scoped>
  77 + .avatar-uploader > .ant-upload {
  78 + width: 128px;
  79 + height: 128px;
  80 + }
  81 +
  82 + .ant-upload-select-picture-card i {
  83 + color: #999;
  84 + font-size: 32px;
  85 + }
  86 +
  87 + .ant-upload-select-picture-card .ant-upload-text {
  88 + margin-top: 8px;
  89 + color: #666;
  90 + }
  91 +</style>
... ...
src/components/Form/src/BasicForm.vue
... ... @@ -117,14 +117,19 @@
117 117 const getSchema = computed((): FormSchema[] => {
118 118 const schemas: FormSchema[] = unref(schemaRef) || (unref(getProps).schemas as any);
119 119 for (const schema of schemas) {
120   - const { defaultValue, component, componentProps,isHandleDateDefaultValue = true } = schema;
  120 + const {
  121 + defaultValue,
  122 + component,
  123 + componentProps,
  124 + isHandleDateDefaultValue = true,
  125 + } = schema;
121 126 // handle date type
122 127 if (isHandleDateDefaultValue && defaultValue && dateItemType.includes(component)) {
123   - const valueFormat =componentProps ? componentProps['valueFormat'] : null;
  128 + const valueFormat = componentProps ? componentProps['valueFormat'] : null;
124 129 if (!Array.isArray(defaultValue)) {
125   - schema.defaultValue = valueFormat
126   - ? dateUtil(defaultValue).format(valueFormat)
127   - : dateUtil(defaultValue);
  130 + schema.defaultValue = valueFormat
  131 + ? dateUtil(defaultValue).format(valueFormat)
  132 + : dateUtil(defaultValue);
128 133 } else {
129 134 const def: any[] = [];
130 135 defaultValue.forEach((item) => {
... ...
src/components/Form/src/componentMap.ts
... ... @@ -29,6 +29,8 @@ import ApiTreeSelect from &#39;./components/ApiTreeSelect.vue&#39;;
29 29 import ApiCascader from './components/ApiCascader.vue';
30 30 import ApiTransfer from './components/ApiTransfer.vue';
31 31 import { BasicUpload } from '/@/components/Upload';
  32 +import FieldUpload from '/@/components/FieldUpload';
  33 +
32 34 import { StrengthMeter } from '/@/components/StrengthMeter';
33 35 import { IconPicker } from '/@/components/Icon';
34 36 import { CountdownInput } from '/@/components/CountDown';
... ... @@ -71,6 +73,7 @@ componentMap.set(&#39;IconPicker&#39;, IconPicker);
71 73 componentMap.set('InputCountDown', CountdownInput);
72 74  
73 75 componentMap.set('Upload', BasicUpload);
  76 +componentMap.set('FieldUpload', FieldUpload);
74 77 componentMap.set('Divider', Divider);
75 78  
76 79 export function add(compName: ComponentType, component: Component) {
... ...
src/components/Form/src/types/index.ts
... ... @@ -110,6 +110,7 @@ export type ComponentType =
110 110 | 'Switch'
111 111 | 'StrengthMeter'
112 112 | 'Upload'
  113 + | 'FieldUpload'
113 114 | 'IconPicker'
114 115 | 'Render'
115 116 | 'Slider'
... ...
src/components/Table/src/BasicTable.vue
... ... @@ -457,4 +457,16 @@
457 457 }
458 458 }
459 459 }
  460 +
  461 + .ant-table {
  462 + font-size: 15px !important;
  463 + }
  464 +
  465 + .ant-table-middle {
  466 + font-size: 14px !important;
  467 + }
  468 +
  469 + .ant-table-small {
  470 + font-size: 13px !important;
  471 + }
460 472 </style>
... ...
src/components/Table/src/components/settings/ColumnSetting.vue
... ... @@ -12,7 +12,7 @@
12 12 >
13 13 <template #title>
14 14 <div :class="`${prefixCls}__popover-title`">
15   - <Checkbox
  15 + <!-- <Checkbox
16 16 :indeterminate="indeterminate"
17 17 v-model:checked="checkAll"
18 18 @change="onCheckAllChange"
... ... @@ -22,7 +22,7 @@
22 22  
23 23 <Checkbox v-model:checked="checkIndex" @change="handleIndexCheckChange">
24 24 {{ t('component.table.settingIndexColumnShow') }}
25   - </Checkbox>
  25 + </Checkbox> -->
26 26  
27 27 <Checkbox
28 28 v-model:checked="checkSelect"
... ... @@ -43,12 +43,12 @@
43 43 <CheckboxGroup v-model:value="checkedList" @change="onChange" ref="columnListRef">
44 44 <template v-for="item in plainOptions" :key="item.value">
45 45 <div :class="`${prefixCls}__check-item`" v-if="!('ifShow' in item && !item.ifShow)">
46   - <DragOutlined class="table-column-drag-icon" />
  46 + <!-- <DragOutlined class="table-column-drag-icon" /> -->
47 47 <Checkbox :value="item.value">
48 48 {{ item.label }}
49 49 </Checkbox>
50 50  
51   - <Tooltip
  51 + <!-- <Tooltip
52 52 placement="bottomLeft"
53 53 :mouseLeaveDelay="0.4"
54 54 :getPopupContainer="getPopupContainer"
... ... @@ -88,7 +88,7 @@
88 88 ]"
89 89 @click="handleColumnFixed(item, 'right')"
90 90 />
91   - </Tooltip>
  91 + </Tooltip> -->
92 92 </div>
93 93 </template>
94 94 </CheckboxGroup>
... ... @@ -156,6 +156,7 @@
156 156 setup(_, { emit, attrs }) {
157 157 const { t } = useI18n();
158 158 const table = useTableContext();
  159 + const originColumns = getColumns(); // 配置的列
159 160  
160 161 const defaultRowSelection = omit(table.getRowSelection(), 'selectedRowKeys');
161 162 let inited = false;
... ... @@ -236,14 +237,37 @@
236 237 const checkList = table
237 238 .getColumns({ ignoreAction: true, ignoreIndex: true })
238 239 .map((item) => {
239   - if (item.defaultHidden) {
240   - return '';
  240 + if (item.children) {
  241 + return item.children.map((item) => {
  242 + if (item.defaultHidden) {
  243 + return '';
  244 + }
  245 + return item.dataIndex || item.title;
  246 + });
  247 + } else {
  248 + if (item.defaultHidden) {
  249 + return '';
  250 + }
  251 + return item.dataIndex || item.title;
241 252 }
242   - return item.dataIndex || item.title;
243 253 })
  254 + .flat()
244 255 .filter(Boolean) as string[];
245   - plainOptions.value = columns;
  256 +
  257 + // plainOptions.value = columns;
246 258 plainSortOptions.value = columns;
  259 + plainOptions.value = columns
  260 + .map((item) => {
  261 + if (item.children) {
  262 + return item.children.map((item) => ({
  263 + ...item,
  264 + label: item.title,
  265 + value: item.dataIndex || item.title,
  266 + }));
  267 + }
  268 + return item;
  269 + })
  270 + .flat();
247 271 // 更新缓存配置
248 272 table.setCacheColumns?.(columns);
249 273 !isReset && (cachePlainOptions.value = cloneDeep(columns));
... ... @@ -282,12 +306,22 @@
282 306 const len = plainSortOptions.value.length;
283 307 state.checkAll = checkedList.length === len;
284 308 const sortList = unref(plainSortOptions).map((item) => item.value);
  309 +
285 310 checkedList.sort((prev, next) => {
286 311 return sortList.indexOf(prev) - sortList.indexOf(next);
287 312 });
288 313 unref(plainSortOptions).forEach((item) => {
289   - (item as BasicColumn).defaultHidden = !checkedList.includes(item.value);
  314 + // 若存在children则,便利children
  315 + if (item.children) {
  316 + item.children.forEach((item) => {
  317 + (item as BasicColumn).defaultHidden = !checkedList.includes(item.value);
  318 + });
  319 + return;
  320 + } else {
  321 + (item as BasicColumn).defaultHidden = !checkedList.includes(item.value);
  322 + }
290 323 });
  324 +
291 325 setColumns(checkedList);
292 326 }
293 327  
... ... @@ -388,17 +422,63 @@
388 422 function setColumns(columns: BasicColumn[] | string[]) {
389 423 isSetPropsFromThis = true;
390 424 isSetColumnsFromThis = true;
391   - table.setColumns(columns);
392   - const data: ColumnChangeParam[] = unref(plainSortOptions).map((col) => {
393   - const visible =
394   - columns.findIndex(
395   - (c: BasicColumn | string) =>
396   - c === col.value || (typeof c !== 'string' && c.dataIndex === col.value),
397   - ) !== -1;
398   - return { dataIndex: col.value, fixed: col.fixed, visible };
399   - });
400 425  
401   - emit('columns-change', data);
  426 + const newColumns = plainSortOptions.value
  427 + .map((col) => {
  428 + if (col.children) {
  429 + return {
  430 + ...col,
  431 + children: col.children.map((c) => {
  432 + if (columns.includes(c.dataIndex as string)) {
  433 + return {
  434 + ...c,
  435 + defaultHidden: false,
  436 + };
  437 + }
  438 + return {
  439 + ...c,
  440 + defaultHidden: true,
  441 + };
  442 + }),
  443 + };
  444 + } else {
  445 + if (columns.includes(col.dataIndex as string)) {
  446 + return {
  447 + ...col,
  448 + defaultHidden: false,
  449 + };
  450 + }
  451 + return {
  452 + ...col,
  453 + defaultHidden: true,
  454 + };
  455 + }
  456 + })
  457 + .filter((col) => {
  458 + if (col.children) {
  459 + const newChildren = col.children.filter((c) => !c.defaultHidden);
  460 + if (!newChildren.length) return false;
  461 + col.children = newChildren;
  462 + return true;
  463 + }
  464 + return !col.defaultHidden;
  465 + });
  466 +
  467 + table.setColumns(newColumns);
  468 +
  469 + // const columns = unref(plainSortOptions).map(col => {
  470 + // if(col.)
  471 + // })
  472 + // const data: ColumnChangeParam[] = unref(plainSortOptions).map((col) => {
  473 + // const visible =
  474 + // columns.findIndex(
  475 + // (c: BasicColumn | string) =>
  476 + // c === col.value || (typeof c !== 'string' && c.dataIndex === col.value),
  477 + // ) !== -1;
  478 + // return { dataIndex: col.value, fixed: col.fixed, visible };
  479 + // });
  480 +
  481 + // emit('columns-change', data);
402 482 }
403 483  
404 484 function getPopupContainer() {
... ... @@ -457,7 +537,7 @@
457 537 display: flex;
458 538 align-items: center;
459 539 min-width: 100%;
460   - padding: 4px 16px 8px 0;
  540 + padding: 4px 16px 8px;
461 541  
462 542 .ant-checkbox-wrapper {
463 543 width: 100%;
... ...
src/components/Table/src/hooks/useDataSource.ts
... ... @@ -307,6 +307,7 @@ export function useDataSource(
307 307 const isArrayResult = Array.isArray(res);
308 308  
309 309 let resultItems: Recordable[] = isArrayResult ? res : get(res, listField);
  310 + console.log('%c [ res ]-311', 'font-size:13px; background:pink; color:#bf2c9f;', res);
310 311 const resultTotal: number = isArrayResult ? res.length : get(res, totalField);
311 312  
312 313 // 假如数据变少,导致总页数变少并小于当前选中页码,通过getPaginationRef获取到的页码是不正确的,需获取正确的页码再次执行
... ...
src/components/Upload/src/FileList.vue
... ... @@ -46,6 +46,12 @@
46 46 </thead>
47 47 <tbody>
48 48 {dataSource.map((record = {}, index) => {
  49 + console.log(
  50 + '%c [ record ]-49',
  51 + 'font-size:13px; background:pink; color:#bf2c9f;',
  52 + record,
  53 + );
  54 +
49 55 return (
50 56 <tr class="file-table-tr" key={`${index + record.name || ''}`}>
51 57 {columnList.map((item) => {
... ...
src/design/theme.less
... ... @@ -50,3 +50,7 @@ html[data-theme=&#39;light&#39;] {
50 50 color: rgb(0 0 0 / 90%);
51 51 }
52 52 }
  53 +
  54 +.ant-message {
  55 + z-index: 9999 !important;
  56 +}
... ...
src/enums/exceptionEnum.ts
... ... @@ -3,7 +3,7 @@
3 3 */
4 4 export enum ExceptionEnum {
5 5 // page not access
6   - PAGE_NOT_ACCESS = 403,
  6 + PAGE_NOT_ACCESS = 404,
7 7  
8 8 // page not found
9 9 PAGE_NOT_FOUND = 404,
... ...
src/enums/pageEnum.ts
... ... @@ -2,7 +2,7 @@ export enum PageEnum {
2 2 // basic login path
3 3 BASE_LOGIN = '/login',
4 4 // basic home path
5   - BASE_HOME = '/dashboard',
  5 + BASE_HOME = '/',
6 6 // error page path
7 7 ERROR_PAGE = '/exception',
8 8 // error log page path
... ...
src/hooks/component/order.ts 0 → 100644
  1 +// useOrderInfo.js
  2 +import { computed } from 'vue';
  3 +import { map } from 'lodash-es';
  4 +
  5 +export function useOrderInfo(orderStore) {
  6 + // 确保 transformDictInfo 函数是可用的,可以将其导入或在此文件中定义
  7 + const transformDictInfo = (item) => ({
  8 + label: item.dictValue,
  9 + value: item.dictValue,
  10 + });
  11 +
  12 + const customerCode = computed(() => {
  13 + const dictInfo = orderStore.getDictInfo;
  14 +
  15 + return map(dictInfo?.customerCode, transformDictInfo);
  16 + });
  17 +
  18 + const projectNo = computed(() => {
  19 + const dictInfo = orderStore.getDictInfo;
  20 + return map(dictInfo?.projectNo, transformDictInfo);
  21 + });
  22 +
  23 + const productionDepartment = computed(() => {
  24 + const dictInfo = orderStore.getDictInfo;
  25 + return map(dictInfo?.productionDepartment, transformDictInfo);
  26 + });
  27 +
  28 + const innerNo = computed(() => {
  29 + const dictInfo = orderStore.getDictInfo;
  30 + return map(dictInfo?.innerNo, transformDictInfo);
  31 + });
  32 +
  33 + const poColor = computed(() => {
  34 + const dictInfo = orderStore.getDictInfo;
  35 + return map(dictInfo?.poColor, transformDictInfo);
  36 + });
  37 +
  38 + const cnColor = computed(() => {
  39 + const dictInfo = orderStore.getDictInfo;
  40 + return map(dictInfo?.cnColor, transformDictInfo);
  41 + });
  42 +
  43 + const productStyle = computed(() => {
  44 + const dictInfo = orderStore.getDictInfo;
  45 + return map(dictInfo?.productStyle, transformDictInfo);
  46 + });
  47 +
  48 + const outboundType = computed(() => {
  49 + const dictInfo = orderStore.getDictInfo;
  50 + return map(dictInfo?.outboundType, transformDictInfo);
  51 + });
  52 +
  53 + const packetType = computed(() => {
  54 + const dictInfo = orderStore.getDictInfo;
  55 + return map(dictInfo?.packetType, transformDictInfo);
  56 + });
  57 +
  58 + const ideaSource = computed(() => {
  59 + const dictInfo = orderStore.getDictInfo;
  60 + return map(dictInfo?.ideaSource, transformDictInfo);
  61 + });
  62 +
  63 + const manualPreform = computed(() => {
  64 + const dictInfo = orderStore.getDictInfo;
  65 + return map(dictInfo?.manualPreform, transformDictInfo);
  66 + });
  67 +
  68 + const endCheckResult = computed(() => {
  69 + const dictInfo = orderStore.getDictInfo;
  70 + return map(dictInfo?.endCheckResult, transformDictInfo);
  71 + });
  72 +
  73 + const midCheckResult = computed(() => {
  74 + const dictInfo = orderStore.getDictInfo;
  75 + return map(dictInfo?.midCheckResult, transformDictInfo);
  76 + });
  77 +
  78 + console.log('%c [ ]-78', 'font-size:13px; background:pink; color:#bf2c9f;', endCheckResult);
  79 + return {
  80 + customerCode,
  81 + projectNo,
  82 + productionDepartment,
  83 + innerNo,
  84 + poColor,
  85 + cnColor,
  86 + productStyle,
  87 + outboundType,
  88 + packetType,
  89 + ideaSource,
  90 + manualPreform,
  91 + midCheckResult,
  92 + endCheckResult,
  93 + };
  94 +}
... ...
src/layouts/default/header/components/user-dropdown/index.vue
... ... @@ -11,7 +11,7 @@
11 11  
12 12 <template #overlay>
13 13 <Menu @click="handleMenuClick">
14   - <MenuItem
  14 + <!-- <MenuItem
15 15 key="doc"
16 16 :text="t('layout.header.dropdownItemDoc')"
17 17 icon="ion:document-text-outline"
... ... @@ -23,7 +23,7 @@
23 23 key="lock"
24 24 :text="t('layout.header.tooltipLock')"
25 25 icon="ion:lock-closed-outline"
26   - />
  26 + /> -->
27 27 <MenuItem
28 28 key="logout"
29 29 :text="t('layout.header.dropdownItemLoginOut')"
... ...
src/layouts/default/header/index.vue
... ... @@ -33,24 +33,24 @@
33 33  
34 34 <!-- action -->
35 35 <div :class="`${prefixCls}-action`">
36   - <AppSearch :class="`${prefixCls}-action__item `" v-if="getShowSearch" />
  36 + <!-- <AppSearch :class="`${prefixCls}-action__item `" v-if="getShowSearch" /> -->
37 37  
38 38 <ErrorAction v-if="getUseErrorHandle" :class="`${prefixCls}-action__item error-action`" />
39 39  
40   - <Notify v-if="getShowNotice" :class="`${prefixCls}-action__item notify-item`" />
  40 + <!-- <Notify v-if="getShowNotice" :class="`${prefixCls}-action__item notify-item`" /> -->
41 41  
42 42 <FullScreen v-if="getShowFullScreen" :class="`${prefixCls}-action__item fullscreen-item`" />
43 43  
44   - <AppLocalePicker
  44 + <!-- <AppLocalePicker
45 45 v-if="getShowLocalePicker"
46 46 :reload="true"
47 47 :showText="false"
48 48 :class="`${prefixCls}-action__item`"
49   - />
  49 + /> -->
50 50  
51 51 <UserDropDown :theme="getHeaderTheme" />
52 52  
53   - <SettingDrawer v-if="getShowSetting" :class="`${prefixCls}-action__item`" />
  53 + <!-- <SettingDrawer v-if="getShowSetting" :class="`${prefixCls}-action__item`" /> -->
54 54 </div>
55 55 </Header>
56 56 </template>
... ...
src/layouts/default/index.vue
... ... @@ -3,9 +3,12 @@
3 3 <LayoutFeatures />
4 4 <LayoutHeader fixed v-if="getShowFullHeaderRef" />
5 5 <Layout :class="[layoutClass]">
  6 + <!-- 左侧菜单 -->
6 7 <LayoutSideBar v-if="getShowSidebar || getIsMobile" />
7 8 <Layout :class="`${prefixCls}-main`">
  9 + <!-- 顶部header -->
8 10 <LayoutMultipleHeader />
  11 + <!-- 内容区域 -->
9 12 <LayoutContent />
10 13 <LayoutFooter />
11 14 </Layout>
... ...
src/layouts/default/menu/index.vue
... ... @@ -140,7 +140,7 @@
140 140  
141 141 function renderMenu() {
142 142 const { menus, ...menuProps } = unref(getCommonProps);
143   - // console.log(menus);
  143 + console.log(menus);
144 144 if (!menus || !menus.length) return null;
145 145 return !props.isHorizontal ? (
146 146 <SimpleMenu {...menuProps} isSplitMenu={unref(getSplit)} items={menus} />
... ...
src/locales/lang/zh-CN/routes/dashboard.ts
1 1 export default {
2 2 dashboard: 'Dashboard',
  3 + home: '首页',
3 4 about: '关于',
4 5 workbench: '工作台',
5 6 analysis: '分析页',
  7 + order: '订单管理',
6 8 };
... ...
src/locales/lang/zh-CN/sys.ts
... ... @@ -67,8 +67,8 @@ export default {
67 67 signUpFormTitle: '注册',
68 68 forgetFormTitle: '重置密码',
69 69  
70   - signInTitle: '开箱即用的中后台管理系统',
71   - signInDesc: '输入您的个人详细信息开始使用!',
  70 + signInTitle: '订单管理系统',
  71 + signInDesc: '',
72 72 policy: '我同意xxx隐私政策',
73 73 scanSign: `扫码后点击"确认",即可完成登录`,
74 74  
... ...
src/main.ts
... ... @@ -40,7 +40,7 @@ async function bootstrap() {
40 40 await setupI18n(app);
41 41  
42 42 // Configure routing
43   - // 配置路由
  43 + // 配置路由,把一些常量不需要权限判断的路有页面放在这里
44 44 setupRouter(app);
45 45  
46 46 // router-guard
... ...
src/router/guard/permissionGuard.ts
... ... @@ -25,7 +25,7 @@ export function createPermissionGuard(router: Router) {
25 25 userStore.getUserInfo.homePath &&
26 26 userStore.getUserInfo.homePath !== PageEnum.BASE_HOME
27 27 ) {
28   - next(userStore.getUserInfo.homePath);
  28 + next('/home');
29 29 return;
30 30 }
31 31  
... ...
src/router/menus/index.ts
... ... @@ -63,10 +63,12 @@ async function getAsyncMenus() {
63 63 return show;
64 64 });
65 65 };
  66 +
66 67 if (isBackMode()) {
67 68 return menuFilter(permissionStore.getBackMenuList);
68 69 }
69   - if (isRouteMappingMode()) {
  70 + // if (isRouteMappingMode()) {
  71 + if (true) {
70 72 return menuFilter(permissionStore.getFrontMenuList);
71 73 }
72 74 return staticMenus;
... ...
src/router/routes/index.ts
... ... @@ -7,7 +7,7 @@ import { PageEnum } from &#39;/@/enums/pageEnum&#39;;
7 7 import { t } from '/@/hooks/web/useI18n';
8 8  
9 9 // import.meta.glob() 直接引入所有的模块 Vite 独有的功能
10   -const modules = import.meta.glob('./modules/**/*.ts', { eager: true });
  10 +const modules = import.meta.glob('./modules/project/*.ts', { eager: true });
11 11 const routeModuleList: AppRouteModule[] = [];
12 12  
13 13 // 加入到路由集合中
... ... @@ -40,6 +40,7 @@ export const LoginRoute: AppRouteRecordRaw = {
40 40  
41 41 // Basic routing without permission
42 42 // 未经许可的基本路由
  43 +// 没有权限要求,所有人都看得到
43 44 export const basicRoutes = [
44 45 LoginRoute,
45 46 RootRoute,
... ...
src/router/routes/modules/demo/system.ts
... ... @@ -21,7 +21,7 @@ const system: AppRouteModule = {
21 21 title: t('routes.demo.system.account'),
22 22 ignoreKeepAlive: false,
23 23 },
24   - component: () => import('/@/views/demo/system/account/index.vue'),
  24 + component: () => import('/@/views/project/system/account/index.vue'),
25 25 },
26 26 {
27 27 path: 'account_detail/:id',
... ... @@ -33,7 +33,7 @@ const system: AppRouteModule = {
33 33 showMenu: false,
34 34 currentActiveMenu: '/system/account',
35 35 },
36   - component: () => import('/@/views/demo/system/account/AccountDetail.vue'),
  36 + component: () => import('/@/views/project/system/account/AccountDetail.vue'),
37 37 },
38 38 {
39 39 path: 'role',
... ...
src/router/routes/modules/project/approve.ts 0 → 100644
  1 +import type { AppRouteModule } from '/@/router/types';
  2 +
  3 +import { LAYOUT } from '/@/router/constant';
  4 +
  5 +const order: AppRouteModule = {
  6 + path: '/approve',
  7 + name: 'Approve',
  8 + component: LAYOUT,
  9 + redirect: '/approve',
  10 + meta: {
  11 + hideChildrenInMenu: true,
  12 + orderNo: 3,
  13 + icon: 'ion:grid-outline',
  14 + title: '审批管理',
  15 + },
  16 + children: [
  17 + {
  18 + path: '',
  19 + name: 'Approve',
  20 + component: () => import('/@/views/project/approve/index.vue'),
  21 + meta: {
  22 + // affix: true,
  23 + title: '审批管理',
  24 + },
  25 + },
  26 + // {
  27 + // path: 'workbench',
  28 + // name: 'Workbench',
  29 + // component: () => import('/@/views/dashboard/workbench/index.vue'),
  30 + // meta: {
  31 + // title: t('routes.dashboard.workbench'),
  32 + // },
  33 + // },
  34 + ],
  35 +};
  36 +
  37 +export default order;
... ...
src/router/routes/modules/dashboard.ts renamed to src/router/routes/modules/project/dashboard.ts
... ... @@ -4,33 +4,34 @@ import { LAYOUT } from &#39;/@/router/constant&#39;;
4 4 import { t } from '/@/hooks/web/useI18n';
5 5  
6 6 const dashboard: AppRouteModule = {
7   - path: '/dashboard',
8   - name: 'Dashboard',
  7 + path: '/home',
  8 + name: 'Analysis',
9 9 component: LAYOUT,
10   - redirect: '/dashboard/analysis',
  10 + redirect: '/home',
11 11 meta: {
12   - orderNo: 10,
  12 + hideChildrenInMenu: true,
  13 + orderNo: 1,
13 14 icon: 'ion:grid-outline',
14   - title: t('routes.dashboard.dashboard'),
  15 + title: t('routes.dashboard.home'),
15 16 },
16 17 children: [
17 18 {
18   - path: 'analysis',
  19 + path: '',
19 20 name: 'Analysis',
20 21 component: () => import('/@/views/dashboard/analysis/index.vue'),
21 22 meta: {
22 23 // affix: true,
23   - title: t('routes.dashboard.analysis'),
24   - },
25   - },
26   - {
27   - path: 'workbench',
28   - name: 'Workbench',
29   - component: () => import('/@/views/dashboard/workbench/index.vue'),
30   - meta: {
31   - title: t('routes.dashboard.workbench'),
  24 + title: '首页',
32 25 },
33 26 },
  27 + // {
  28 + // path: 'workbench',
  29 + // name: 'Workbench',
  30 + // component: () => import('/@/views/dashboard/workbench/index.vue'),
  31 + // meta: {
  32 + // title: t('routes.dashboard.workbench'),
  33 + // },
  34 + // },
34 35 ],
35 36 };
36 37  
... ...
src/router/routes/modules/project/order.ts 0 → 100644
  1 +import type { AppRouteModule } from '/@/router/types';
  2 +
  3 +import { LAYOUT } from '/@/router/constant';
  4 +import { t } from '/@/hooks/web/useI18n';
  5 +
  6 +const order: AppRouteModule = {
  7 + path: '/order',
  8 + name: 'Order',
  9 + component: LAYOUT,
  10 + redirect: '/order',
  11 + meta: {
  12 + hideChildrenInMenu: true,
  13 + orderNo: 2,
  14 + icon: 'ion:grid-outline',
  15 + title: '订单管理',
  16 + },
  17 + children: [
  18 + {
  19 + path: '',
  20 + name: 'Order',
  21 + component: () => import('/@/views/project/order/index.vue'),
  22 + meta: {
  23 + // affix: true,
  24 + title: '订单管理',
  25 + },
  26 + },
  27 + // {
  28 + // path: 'workbench',
  29 + // name: 'Workbench',
  30 + // component: () => import('/@/views/dashboard/workbench/index.vue'),
  31 + // meta: {
  32 + // title: t('routes.dashboard.workbench'),
  33 + // },
  34 + // },
  35 + ],
  36 +};
  37 +
  38 +export default order;
... ...
src/router/routes/modules/project/system.ts 0 → 100644
  1 +import type { AppRouteModule } from '/@/router/types';
  2 +
  3 +import { LAYOUT } from '/@/router/constant';
  4 +import { t } from '/@/hooks/web/useI18n';
  5 +
  6 +const system: AppRouteModule = {
  7 + path: '/system',
  8 + name: 'System',
  9 + component: LAYOUT,
  10 + redirect: '/system/account',
  11 + meta: {
  12 + orderNo: 3,
  13 + icon: 'ion:settings-outline',
  14 + title: t('routes.demo.system.moduleName'),
  15 + },
  16 + children: [
  17 + {
  18 + path: 'account',
  19 + name: 'AccountManagement',
  20 + meta: {
  21 + title: t('routes.demo.system.account'),
  22 + ignoreKeepAlive: false,
  23 + },
  24 + component: () => import('/@/views/project/account/index.vue'),
  25 + },
  26 + {
  27 + path: 'account_detail/:id',
  28 + name: 'AccountDetail',
  29 + meta: {
  30 + hideMenu: true,
  31 + title: t('routes.demo.system.account_detail'),
  32 + ignoreKeepAlive: true,
  33 + showMenu: false,
  34 + currentActiveMenu: '/system/account',
  35 + },
  36 + component: () => import('/@/views/project/account/AccountDetail.vue'),
  37 + },
  38 + // {
  39 + // path: 'role',
  40 + // name: 'RoleManagement',
  41 + // meta: {
  42 + // title: t('routes.demo.system.role'),
  43 + // ignoreKeepAlive: true,
  44 + // },
  45 + // component: () => import('/@/views/demo/system/role/index.vue'),
  46 + // },
  47 + // {
  48 + // path: 'menu',
  49 + // name: 'MenuManagement',
  50 + // meta: {
  51 + // title: t('routes.demo.system.menu'),
  52 + // ignoreKeepAlive: true,
  53 + // },
  54 + // component: () => import('/@/views/demo/system/menu/index.vue'),
  55 + // },
  56 + // {
  57 + // path: 'dept',
  58 + // name: 'DeptManagement',
  59 + // meta: {
  60 + // title: t('routes.demo.system.dept'),
  61 + // ignoreKeepAlive: true,
  62 + // },
  63 + // component: () => import('/@/views/demo/system/dept/index.vue'),
  64 + // },
  65 + // {
  66 + // path: 'changePassword',
  67 + // name: 'ChangePassword',
  68 + // meta: {
  69 + // title: t('routes.demo.system.password'),
  70 + // ignoreKeepAlive: true,
  71 + // },
  72 + // component: () => import('/@/views/demo/system/password/index.vue'),
  73 + // },
  74 + ],
  75 +};
  76 +
  77 +export default system;
... ...
src/settings/projectSetting.ts
... ... @@ -25,6 +25,7 @@ const setting: ProjectConfig = {
25 25 settingButtonPosition: SettingButtonPositionEnum.AUTO,
26 26  
27 27 // Permission mode
  28 + // permissionMode: PermissionModeEnum.ROLE,
28 29 permissionMode: PermissionModeEnum.ROUTE_MAPPING,
29 30  
30 31 // Permission-related cache is stored in sessionStorage or localStorage
... ...
src/store/modules/app.ts
... ... @@ -48,6 +48,11 @@ export const useAppStore = defineStore({
48 48 },
49 49  
50 50 getProjectConfig(state): ProjectConfig {
  51 + console.log(
  52 + '%c [ state.projectConfig ]-52',
  53 + 'font-size:13px; background:pink; color:#bf2c9f;',
  54 + state.projectConfig,
  55 + );
51 56 return state.projectConfig || ({} as ProjectConfig);
52 57 },
53 58  
... ...
src/store/modules/data.ts 0 → 100644
  1 +import { forEach } from '/@/utils/helper/treeHelper';
  2 +import type { UserInfo } from '/#/store';
  3 +import { defineStore } from 'pinia';
  4 +import { store } from '/@/store';
  5 +import { RoleEnum } from '/@/enums/roleEnum';
  6 +
  7 +import { getApiData, getChartData } from '/@/api/project/global';
  8 +import { formatToDate } from '/@/utils/dateUtil';
  9 +
  10 +interface UserState {
  11 + userInfo: Nullable<UserInfo>;
  12 + token?: string;
  13 + roleList: RoleEnum[];
  14 + sessionTimeout?: boolean;
  15 + lastUpdateTime: number;
  16 +}
  17 +
  18 +export const useDataStore = defineStore({
  19 + id: 'app-data',
  20 + state: (): UserState => ({
  21 + // user info
  22 + data: {},
  23 + // token
  24 + chartData: {},
  25 + }),
  26 + getters: {
  27 + getData(state) {
  28 + return state.data;
  29 + },
  30 + getChartData(state) {
  31 + return state.chartData;
  32 + },
  33 + },
  34 + actions: {
  35 + setData(info) {
  36 + this.data = info ? info : '';
  37 + },
  38 + setChartData(data) {
  39 + this.chartData = data;
  40 + },
  41 +
  42 + async getFetchData(): Promise<any> {
  43 + try {
  44 + const data = await getApiData();
  45 + this.data = data;
  46 + } catch (error) {
  47 + return Promise.reject(error);
  48 + }
  49 + },
  50 + async getFetchChartData(): Promise<any> {
  51 + try {
  52 + const data = await getChartData();
  53 + const x = [],
  54 + y = [];
  55 + data.forEach((value) => {
  56 + x.push(formatToDate(value.dateTime));
  57 + y.push(value.orderCount);
  58 + });
  59 + this.chartData = { x, y };
  60 + } catch (error) {
  61 + return Promise.reject(error);
  62 + }
  63 + },
  64 + },
  65 +});
  66 +
  67 +// Need to be used outside the setup
  68 +export function useDataStoreWithOut() {
  69 + return useDataStore(store);
  70 +}
... ...
src/store/modules/order.ts 0 → 100644
  1 +import type { UserInfo } from '/#/store';
  2 +import type { ErrorMessageMode } from '/#/axios';
  3 +import { defineStore } from 'pinia';
  4 +import { store } from '/@/store';
  5 +import { RoleEnum } from '/@/enums/roleEnum';
  6 +import { PageEnum } from '/@/enums/pageEnum';
  7 +import { ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum';
  8 +import { getAuthCache, setAuthCache } from '/@/utils/auth';
  9 +import { GetUserInfoModel, LoginParams } from '/@/api/sys/model/userModel';
  10 +import { doLogout, getUserInfo, loginApi, getImageCaptcha } from '/@/api/sys/user';
  11 +import { useI18n } from '/@/hooks/web/useI18n';
  12 +import { useMessage } from '/@/hooks/web/useMessage';
  13 +import { router } from '/@/router';
  14 +import { usePermissionStore } from '/@/store/modules/permission';
  15 +import { RouteRecordRaw } from 'vue-router';
  16 +import { PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';
  17 +import { h } from 'vue';
  18 +import { getInitDictData } from '/@/api/project/order';
  19 +import { groupBy } from 'lodash-es';
  20 +
  21 +interface UserState {
  22 + userInfo: Nullable<UserInfo>;
  23 + token?: string;
  24 + roleList: RoleEnum[];
  25 + sessionTimeout?: boolean;
  26 + lastUpdateTime: number;
  27 +}
  28 +
  29 +export const useOrderStore = defineStore({
  30 + id: 'app-order',
  31 + state: (): UserState => ({
  32 + // user info
  33 + dicts: {},
  34 + // token
  35 + total: 0,
  36 + // roleList
  37 + roleList: [],
  38 + // Whether the login expired
  39 + sessionTimeout: false,
  40 + // Last fetch time
  41 + lastUpdateTime: 0,
  42 + }),
  43 + getters: {
  44 + getDictInfo(state): UserInfo {
  45 + return state.dicts;
  46 + },
  47 + getTotal(state) {
  48 + return state.total;
  49 + },
  50 + getToken(state): string {
  51 + return state.token || getAuthCache<string>(TOKEN_KEY);
  52 + },
  53 + getRoleList(state): RoleEnum[] {
  54 + return state.roleList.length > 0 ? state.roleList : getAuthCache<RoleEnum[]>(ROLES_KEY);
  55 + },
  56 + getSessionTimeout(state): boolean {
  57 + return !!state.sessionTimeout;
  58 + },
  59 + getLastUpdateTime(state): number {
  60 + return state.lastUpdateTime;
  61 + },
  62 + },
  63 + actions: {
  64 + setToken(info: string | undefined) {
  65 + this.token = info ? info : ''; // for null or undefined value
  66 + setAuthCache(TOKEN_KEY, info);
  67 + },
  68 + setTotal(total) {
  69 + this.total = total;
  70 + },
  71 + setRoleList(roleList: RoleEnum[]) {
  72 + this.roleList = roleList;
  73 + setAuthCache(ROLES_KEY, roleList);
  74 + },
  75 + setUserInfo(info: UserInfo | null) {
  76 + this.userInfo = info;
  77 + this.lastUpdateTime = new Date().getTime();
  78 + setAuthCache(USER_INFO_KEY, info);
  79 + },
  80 + setSessionTimeout(flag: boolean) {
  81 + this.sessionTimeout = flag;
  82 + },
  83 + resetState() {
  84 + this.userInfo = null;
  85 + this.token = '';
  86 + this.roleList = [];
  87 + this.sessionTimeout = false;
  88 + },
  89 + /**
  90 + * @description: login
  91 + */
  92 + async getDict(): Promise<GetUserInfoModel | null> {
  93 + try {
  94 + const data = await getInitDictData();
  95 + console.log('%c [ data ]-95', 'font-size:13px; background:pink; color:#bf2c9f;', data);
  96 + this.dicts = groupBy(data, 'dictCode');
  97 + } catch (error) {
  98 + return Promise.reject(error);
  99 + }
  100 + },
  101 + async afterLoginAction(userInfo): Promise<GetUserInfoModel | null> {
  102 + if (!this.getToken) return null;
  103 + // get user info
  104 + // const userInfo = await this.getUserInfoAction();
  105 +
  106 + const sessionTimeout = this.sessionTimeout;
  107 + if (sessionTimeout) {
  108 + this.setSessionTimeout(false);
  109 + } else {
  110 + const permissionStore = usePermissionStore();
  111 + if (!permissionStore.isDynamicAddedRoute) {
  112 + const routes = await permissionStore.buildRoutesAction();
  113 + routes.forEach((route) => {
  114 + router.addRoute(route as unknown as RouteRecordRaw);
  115 + });
  116 + router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw);
  117 + permissionStore.setDynamicAddedRoute(true);
  118 + }
  119 + await router.replace('home');
  120 + }
  121 + return userInfo;
  122 + },
  123 + async getUserInfoAction(): Promise<UserInfo | null> {
  124 + // if (!this.getToken) return null;
  125 + // const userInfo = await getUserInfo();
  126 + // const { roles = [] } = userInfo;
  127 + // if (isArray(roles)) {
  128 + // const roleList = roles.map((item) => item.value) as RoleEnum[];
  129 + // this.setRoleList(roleList);
  130 + // } else {
  131 + // userInfo.roles = [];
  132 + // this.setRoleList([]);
  133 + // }
  134 + // this.setUserInfo(userInfo);
  135 + // return userInfo;
  136 + return {};
  137 + },
  138 + /**
  139 + * @description: logout
  140 + */
  141 + async logout(goLogin = false) {
  142 + if (this.getToken) {
  143 + try {
  144 + await doLogout();
  145 + } catch {
  146 + console.log('注销Token失败');
  147 + }
  148 + }
  149 + this.setToken(undefined);
  150 + this.setSessionTimeout(false);
  151 + this.setUserInfo(null);
  152 + goLogin && router.push(PageEnum.BASE_LOGIN);
  153 + },
  154 +
  155 + /**
  156 + * @description: Confirm before logging out
  157 + */
  158 + confirmLoginOut() {
  159 + const { createConfirm } = useMessage();
  160 + const { t } = useI18n();
  161 + createConfirm({
  162 + iconType: 'warning',
  163 + title: () => h('span', t('sys.app.logoutTip')),
  164 + content: () => h('span', t('sys.app.logoutMessage')),
  165 + onOk: async () => {
  166 + await this.logout(true);
  167 + },
  168 + });
  169 + },
  170 +
  171 + /**
  172 + * 获取图片验证码
  173 + */
  174 + async getImageCaptcha() {
  175 + return await getImageCaptcha();
  176 + },
  177 + },
  178 +});
  179 +
  180 +// Need to be used outside the setup
  181 +export function useOrderStoreWithOut() {
  182 + return useOrderStore(store);
  183 +}
... ...
src/store/modules/permission.ts
... ... @@ -116,8 +116,10 @@ export const usePermissionStore = defineStore({
116 116  
117 117 let routes: AppRouteRecordRaw[] = [];
118 118 const roleList = toRaw(userStore.getRoleList) || [];
119   - const { permissionMode = projectSetting.permissionMode } = appStore.getProjectConfig;
120   -
  119 + // dddd
  120 + // const { permissionMode = projectSetting.permissionMode } = appStore.getProjectConfig;
  121 + const permissionMode = projectSetting.permissionMode;
  122 + // const permissionMode = PermissionModeEnum.ROUTE_MAPPING;
121 123 // 路由过滤器 在 函数filter 作为回调传入遍历使用
122 124 const routeFilter = (route: AppRouteRecordRaw) => {
123 125 const { meta } = route;
... ... @@ -167,7 +169,6 @@ export const usePermissionStore = defineStore({
167 169 }
168 170 return;
169 171 };
170   -
171 172 switch (permissionMode) {
172 173 // 角色权限
173 174 case PermissionModeEnum.ROLE:
... ... @@ -178,6 +179,8 @@ export const usePermissionStore = defineStore({
178 179 // Convert multi-level routing to level 2 routing
179 180 // 将多级路由转换为 2 级路由
180 181 routes = flatMultiLevelRoutes(routes);
  182 +
  183 + routes = asyncRoutes;
181 184 break;
182 185  
183 186 // 路由映射, 默认进入该case
... ...
src/store/modules/user.ts
... ... @@ -7,7 +7,7 @@ import { PageEnum } from &#39;/@/enums/pageEnum&#39;;
7 7 import { ROLES_KEY, TOKEN_KEY, USER_INFO_KEY } from '/@/enums/cacheEnum';
8 8 import { getAuthCache, setAuthCache } from '/@/utils/auth';
9 9 import { GetUserInfoModel, LoginParams } from '/@/api/sys/model/userModel';
10   -import { doLogout, getUserInfo, loginApi } from '/@/api/sys/user';
  10 +import { doLogout, getUserInfo, loginApi, getImageCaptcha } from '/@/api/sys/user';
11 11 import { useI18n } from '/@/hooks/web/useI18n';
12 12 import { useMessage } from '/@/hooks/web/useMessage';
13 13 import { router } from '/@/router';
... ... @@ -89,21 +89,24 @@ export const useUserStore = defineStore({
89 89 },
90 90 ): Promise<GetUserInfoModel | null> {
91 91 try {
92   - const { goHome = true, mode, ...loginParams } = params;
  92 + const { mode, ...loginParams } = params;
93 93 const data = await loginApi(loginParams, mode);
94   - const { token } = data;
  94 + const { token, user } = data;
95 95  
96   - // save token
97 96 this.setToken(token);
98   - return this.afterLoginAction(goHome);
  97 + // this.setToken(
  98 + // 'Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImF1dGgiOiJkZXB0OmVkaXQsdXNlcjpsaXN0LHJvbGVzOmFkZCx1c2VyOmFkZCxkZXB0OmFkZCxtZW51OmRlbCxyb2xlczpkZWwsbWVudTplZGl0LG1lbnU6bGlzdCxzdG9yYWdlOmxpc3Qsam9iOmVkaXQscm9sZXM6bGlzdCx1c2VyOmRlbCxkaWN0OmFkZCxkZXB0Omxpc3QsbWVudTphZGQsam9iOmRlbCxqb2I6bGlzdCx1c2VyOmVkaXQscm9sZXM6ZWRpdCxkaWN0OmRlbCxqb2I6YWRkLGRpY3Q6ZWRpdCxkZXB0OmRlbCIsImV4cCI6MTY5NjE0NTUzN30.Q9hcwnG9uJP3HHjwpd_3ZrV7LrZlMIL6JJBe0rcfqldE8SPq8JkBKElrGeu7GoCAc5EyN6wUUYcriwV5VhpZqQ',
  99 + // );
  100 + // 'Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ4bXMiLCJhdXRoIjoiZGVwdDplZGl0LHVzZXI6bGlzdCxyb2xlczphZGQsdXNlcjphZGQsZGVwdDphZGQsbWVudTpkZWwscm9sZXM6ZGVsLG1lbnU6ZWRpdCxtZW51Omxpc3Qsc3RvcmFnZTpsaXN0LGpvYjplZGl0LHJvbGVzOmxpc3QsdXNlcjpkZWwsZGljdDphZGQsZGVwdDpsaXN0LG1lbnU6YWRkLGpvYjpkZWwsam9iOmxpc3QsdXNlcjplZGl0LHJvbGVzOmVkaXQsZGljdDpkZWwsam9iOmFkZCxkaWN0OmVkaXQsZGVwdDpkZWwiLCJleHAiOjE2OTUxNDIwNDF9.Wj-CyJGbMps_9a84TQkJgBSNnj22OVAEVLsEKvVHdyxkQORIwvxpOzT7gr2l-8VbUJ3wLatG0OUe-6smoaoTbA',
  101 + return this.afterLoginAction(user);
99 102 } catch (error) {
100 103 return Promise.reject(error);
101 104 }
102 105 },
103   - async afterLoginAction(goHome?: boolean): Promise<GetUserInfoModel | null> {
  106 + async afterLoginAction(userInfo): Promise<GetUserInfoModel | null> {
104 107 if (!this.getToken) return null;
105 108 // get user info
106   - const userInfo = await this.getUserInfoAction();
  109 + // const userInfo = await this.getUserInfoAction();
107 110  
108 111 const sessionTimeout = this.sessionTimeout;
109 112 if (sessionTimeout) {
... ... @@ -118,39 +121,40 @@ export const useUserStore = defineStore({
118 121 router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw);
119 122 permissionStore.setDynamicAddedRoute(true);
120 123 }
121   - goHome && (await router.replace(userInfo?.homePath || PageEnum.BASE_HOME));
  124 + await router.replace('home');
122 125 }
123 126 return userInfo;
124 127 },
125 128 async getUserInfoAction(): Promise<UserInfo | null> {
126   - if (!this.getToken) return null;
127   - const userInfo = await getUserInfo();
128   - const { roles = [] } = userInfo;
129   - if (isArray(roles)) {
130   - const roleList = roles.map((item) => item.value) as RoleEnum[];
131   - this.setRoleList(roleList);
132   - } else {
133   - userInfo.roles = [];
134   - this.setRoleList([]);
135   - }
136   - this.setUserInfo(userInfo);
137   - return userInfo;
  129 + // if (!this.getToken) return null;
  130 + // const userInfo = await getUserInfo();
  131 + // const { roles = [] } = userInfo;
  132 + // if (isArray(roles)) {
  133 + // const roleList = roles.map((item) => item.value) as RoleEnum[];
  134 + // this.setRoleList(roleList);
  135 + // } else {
  136 + // userInfo.roles = [];
  137 + // this.setRoleList([]);
  138 + // }
  139 + // this.setUserInfo(userInfo);
  140 + // return userInfo;
  141 + return {};
138 142 },
139 143 /**
140 144 * @description: logout
141 145 */
142 146 async logout(goLogin = false) {
143   - if (this.getToken) {
144   - try {
145   - await doLogout();
146   - } catch {
147   - console.log('注销Token失败');
148   - }
149   - }
  147 + // if (this.getToken) {
  148 + // try {
  149 + // await doLogout();
  150 + // } catch {
  151 + // console.log('注销Token失败');
  152 + // }
  153 + // }
150 154 this.setToken(undefined);
151 155 this.setSessionTimeout(false);
152 156 this.setUserInfo(null);
153   - goLogin && router.push(PageEnum.BASE_LOGIN);
  157 + router.push(PageEnum.BASE_LOGIN);
154 158 },
155 159  
156 160 /**
... ... @@ -168,6 +172,13 @@ export const useUserStore = defineStore({
168 172 },
169 173 });
170 174 },
  175 +
  176 + /**
  177 + * 获取图片验证码
  178 + */
  179 + async getImageCaptcha() {
  180 + return await getImageCaptcha();
  181 + },
171 182 },
172 183 });
173 184  
... ...
src/utils/http/axios/Axios.ts
... ... @@ -13,8 +13,12 @@ import { AxiosCanceler } from &#39;./axiosCancel&#39;;
13 13 import { isFunction } from '/@/utils/is';
14 14 import { cloneDeep } from 'lodash-es';
15 15 import { ContentTypeEnum, RequestEnum } from '/@/enums/httpEnum';
  16 +import { useMessage } from '/@/hooks/web/useMessage';
  17 +import { router } from '/@/router';
  18 +import { useUserStoreWithOut } from '/@/store/modules/user';
16 19  
17 20 export * from './axiosTransform';
  21 +const { createMessage } = useMessage();
18 22  
19 23 /**
20 24 * @description: axios module
... ... @@ -206,6 +210,7 @@ export class VAxios {
206 210 const transform = this.getTransform();
207 211  
208 212 const { requestOptions } = this.options;
  213 + const { message } = options || {};
209 214  
210 215 const opt: RequestOptions = Object.assign({}, requestOptions, options);
211 216  
... ... @@ -218,9 +223,23 @@ export class VAxios {
218 223 conf = this.supportFormData(conf);
219 224  
220 225 return new Promise((resolve, reject) => {
  226 + const userStore = useUserStoreWithOut();
  227 +
221 228 this.axiosInstance
222 229 .request<any, AxiosResponse<Result>>(conf)
223 230 .then((res: AxiosResponse<Result>) => {
  231 + if (res.data.result === 401) {
  232 + userStore.setToken('');
  233 + createMessage.error(res.data.message);
  234 + return router.push('/login');
  235 + }
  236 + if (res.data.result !== 0 && res.data.message) {
  237 + return createMessage.error(res.data.message);
  238 + }
  239 +
  240 + if (message && res.data.result === 0) {
  241 + createMessage.success(message);
  242 + }
224 243 if (transformResponseHook && isFunction(transformResponseHook)) {
225 244 try {
226 245 const ret = transformResponseHook(res, opt);
... ... @@ -233,6 +252,7 @@ export class VAxios {
233 252 resolve(res as unknown as Promise<T>);
234 253 })
235 254 .catch((e: Error | AxiosError) => {
  255 + console.log('%c [ e ]-257', 'font-size:13px; background:pink; color:#bf2c9f;', e);
236 256 if (requestCatchHook && isFunction(requestCatchHook)) {
237 257 reject(requestCatchHook(e, opt));
238 258 return;
... ...
src/utils/http/axios/index.ts
... ... @@ -45,16 +45,16 @@ const transform: AxiosTransform = {
45 45 }
46 46 // 错误的时候返回
47 47  
48   - const { data } = res;
49   - if (!data) {
  48 + const { data: bodyData } = res;
  49 + if (!bodyData) {
50 50 // return '[HTTP] Request has no return value';
51 51 throw new Error(t('sys.api.apiRequestFailed'));
52 52 }
53 53 // 这里 code,result,message为 后台统一的字段,需要在 types.ts内修改为项目自己的接口返回格式
54   - const { code, result, message } = data;
  54 + const { result, data, message } = bodyData;
55 55  
56 56 // 这里逻辑可以根据项目进行修改
57   - const hasSuccess = data && Reflect.has(data, 'code') && code === ResultEnum.SUCCESS;
  57 + const hasSuccess = bodyData && Reflect.has(bodyData, 'result') && result === ResultEnum.SUCCESS;
58 58 if (hasSuccess) {
59 59 let successMsg = message;
60 60  
... ... @@ -67,13 +67,13 @@ const transform: AxiosTransform = {
67 67 } else if (options.successMessageMode === 'message') {
68 68 createMessage.success(successMsg);
69 69 }
70   - return result;
  70 + return data;
71 71 }
72 72  
73 73 // 在此处根据自己项目的实际情况对不同的code执行不同的操作
74 74 // 如果不希望中断当前请求,请return数据,否则直接抛出异常即可
75 75 let timeoutMsg = '';
76   - switch (code) {
  76 + switch (result) {
77 77 case ResultEnum.TIMEOUT:
78 78 timeoutMsg = t('sys.api.timeoutMessage');
79 79 const userStore = useUserStoreWithOut();
... ...
src/utils/project.ts 0 → 100644
  1 +export const getDisable = (code, id) => {
  2 + return code === 'LOCKED' && !!id;
  3 +};
... ...
src/views/dashboard/analysis/components/GrowCard.vue
... ... @@ -6,21 +6,21 @@
6 6 :loading="loading"
7 7 :title="item.title"
8 8 class="md:w-1/4 w-full !md:mt-0"
9   - :class="{ '!md:mr-4': index + 1 < 4, '!mt-4': index > 0 }"
  9 + :class="{ '!md:mr-4': index + 1 < 5, '!mt-4': index > 0 }"
10 10 >
11   - <template #extra>
  11 + <!-- <template #extra>
12 12 <Tag :color="item.color">{{ item.action }}</Tag>
13   - </template>
  13 + </template> -->
14 14  
15 15 <div class="py-4 px-4 flex justify-between items-center">
16   - <CountTo prefix="$" :startVal="1" :endVal="item.value" class="text-2xl" />
17   - <Icon :icon="item.icon" :size="40" />
  16 + <CountTo :startVal="1" :endVal="item.value" class="text-2xl" />
  17 + <!-- <Icon :icon="item.icon" :size="40" /> -->
18 18 </div>
19 19  
20   - <div class="p-2 px-4 flex justify-between">
  20 + <!-- <div class="p-2 px-4 flex justify-between">
21 21 <span>总{{ item.title }}</span>
22 22 <CountTo prefix="$" :startVal="1" :endVal="item.total" />
23   - </div>
  23 + </div> -->
24 24 </Card>
25 25 </template>
26 26 </div>
... ... @@ -30,6 +30,56 @@
30 30 import Icon from '@/components/Icon/Icon.vue';
31 31 import { Tag, Card } from 'ant-design-vue';
32 32 import { growCardList } from '../data';
  33 + import { useDataStoreWithOut } from '/@/store/modules/data';
  34 + import { computed } from 'vue';
  35 +
  36 + const dataStore = useDataStoreWithOut();
  37 +
  38 + const growCardList = computed(() => {
  39 + const data = dataStore.getData;
  40 + return [
  41 + {
  42 + title: '订单完成',
  43 + icon: 'visit-count|svg',
  44 + value: data?.orderFinishedCount || 0,
  45 + total: 120000,
  46 + color: 'green',
  47 + action: '月',
  48 + },
  49 + {
  50 + title: '跟单和质检中',
  51 + icon: 'total-sales|svg',
  52 + value: data?.orderInspectingCount || 0,
  53 + total: 500000,
  54 + color: 'blue',
  55 + action: '月',
  56 + },
  57 + {
  58 + title: '利润分析表待审核',
  59 + icon: 'download-count|svg',
  60 + value: data?.orderProfitWaitAuditCount || 0,
  61 + total: 120000,
  62 + color: 'orange',
  63 + action: '周',
  64 + },
  65 + {
  66 + title: '项目报告书待审核',
  67 + icon: 'transaction|svg',
  68 + value: data?.orderReportWaitAuditCount || 0,
  69 + total: 50000,
  70 + color: 'purple',
  71 + action: '年',
  72 + },
  73 + {
  74 + title: '订单初始化',
  75 + icon: 'transaction|svg',
  76 + value: 5000,
  77 + total: 50000,
  78 + color: 'purple',
  79 + action: '年',
  80 + },
  81 + ];
  82 + });
33 83  
34 84 defineProps({
35 85 loading: {
... ...
src/views/dashboard/analysis/components/SiteAnalysis.vue
... ... @@ -24,12 +24,12 @@
24 24 const tabListTitle = [
25 25 {
26 26 key: 'tab1',
27   - tab: '流量趋势',
28   - },
29   - {
30   - key: 'tab2',
31   - tab: '访问量',
  27 + tab: '订单趋势',
32 28 },
  29 + // {
  30 + // key: 'tab2',
  31 + // tab: '访问量',
  32 + // },
33 33 ];
34 34  
35 35 function onTabChange(key) {
... ...
src/views/dashboard/analysis/components/VisitAnalysis.vue
1 1 <template>
2 2 <div ref="chartRef" :style="{ height, width }"></div>
3 3 </template>
4   -<script lang="ts">
5   - import { basicProps } from './props';
6   -</script>
  4 +
7 5 <script lang="ts" setup>
8   - import { onMounted, ref, Ref } from 'vue';
  6 + import { ref, Ref, watchEffect } from 'vue';
9 7 import { useECharts } from '/@/hooks/web/useECharts';
  8 + import { basicProps } from './props';
  9 + import { max } from 'lodash-es';
  10 + import { useDataStoreWithOut } from '/@/store/modules/data';
10 11  
11 12 defineProps({
12 13 ...basicProps,
13 14 });
14 15 const chartRef = ref<HTMLDivElement | null>(null);
15 16 const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
16   -
17   - onMounted(() => {
  17 + const dataStore = useDataStoreWithOut();
  18 + watchEffect(() => {
  19 + const data = dataStore?.getChartData || {};
  20 + const maxY = data?.y ? max(data?.y) : 0;
18 21 setOptions({
19 22 tooltip: {
20 23 trigger: 'axis',
... ... @@ -28,7 +31,7 @@
28 31 xAxis: {
29 32 type: 'category',
30 33 boundaryGap: false,
31   - data: [...new Array(18)].map((_item, index) => `${index + 6}:00`),
  34 + data: data?.x,
32 35 splitLine: {
33 36 show: true,
34 37 lineStyle: {
... ... @@ -44,7 +47,7 @@
44 47 yAxis: [
45 48 {
46 49 type: 'value',
47   - max: 80000,
  50 + max: maxY + 20,
48 51 splitNumber: 4,
49 52 axisTick: {
50 53 show: false,
... ... @@ -61,28 +64,25 @@
61 64 series: [
62 65 {
63 66 smooth: true,
64   - data: [
65   - 111, 222, 4000, 18000, 33333, 55555, 66666, 33333, 14000, 36000, 66666, 44444, 22222,
66   - 11111, 4000, 2000, 500, 333, 222, 111,
67   - ],
  67 + data: data?.y,
68 68 type: 'line',
69 69 areaStyle: {},
70 70 itemStyle: {
71 71 color: '#5ab1ef',
72 72 },
73 73 },
74   - {
75   - smooth: true,
76   - data: [
77   - 33, 66, 88, 333, 3333, 5000, 18000, 3000, 1200, 13000, 22000, 11000, 2221, 1201, 390,
78   - 198, 60, 30, 22, 11,
79   - ],
80   - type: 'line',
81   - areaStyle: {},
82   - itemStyle: {
83   - color: '#019680',
84   - },
85   - },
  74 + // {
  75 + // smooth: true,
  76 + // data: [
  77 + // 33, 66, 88, 333, 3333, 5000, 18000, 3000, 1200, 13000, 22000, 11000, 2221, 1201, 390,
  78 + // 198, 60, 30, 22, 11,
  79 + // ],
  80 + // type: 'line',
  81 + // areaStyle: {},
  82 + // itemStyle: {
  83 + // color: '#019680',
  84 + // },
  85 + // },
86 86 ],
87 87 });
88 88 });
... ...
src/views/dashboard/analysis/data.ts
... ... @@ -9,7 +9,7 @@ export interface GrowCardItem {
9 9  
10 10 export const growCardList: GrowCardItem[] = [
11 11 {
12   - title: '访问数',
  12 + title: '订单完成',
13 13 icon: 'visit-count|svg',
14 14 value: 2000,
15 15 total: 120000,
... ... @@ -17,7 +17,7 @@ export const growCardList: GrowCardItem[] = [
17 17 action: '月',
18 18 },
19 19 {
20   - title: '成交额',
  20 + title: '跟单和质检中',
21 21 icon: 'total-sales|svg',
22 22 value: 20000,
23 23 total: 500000,
... ... @@ -25,7 +25,7 @@ export const growCardList: GrowCardItem[] = [
25 25 action: '月',
26 26 },
27 27 {
28   - title: '下载数',
  28 + title: '利润分析表待审核',
29 29 icon: 'download-count|svg',
30 30 value: 8000,
31 31 total: 120000,
... ... @@ -33,7 +33,15 @@ export const growCardList: GrowCardItem[] = [
33 33 action: '周',
34 34 },
35 35 {
36   - title: '成交数',
  36 + title: '项目报告书待审核',
  37 + icon: 'transaction|svg',
  38 + value: 5000,
  39 + total: 50000,
  40 + color: 'purple',
  41 + action: '年',
  42 + },
  43 + {
  44 + title: '订单初始化',
37 45 icon: 'transaction|svg',
38 46 value: 5000,
39 47 total: 50000,
... ...
src/views/dashboard/analysis/index.vue
... ... @@ -2,22 +2,26 @@
2 2 <div class="p-4">
3 3 <GrowCard :loading="loading" class="enter-y" />
4 4 <SiteAnalysis class="!my-4 enter-y" :loading="loading" />
5   - <div class="md:flex enter-y">
  5 + <!-- <div class="md:flex enter-y">
6 6 <VisitRadar class="md:w-1/3 w-full" :loading="loading" />
7 7 <VisitSource class="md:w-1/3 !md:mx-4 !md:my-0 !my-4 w-full" :loading="loading" />
8 8 <SalesProductPie class="md:w-1/3 w-full" :loading="loading" />
9   - </div>
  9 + </div> -->
10 10 </div>
11 11 </template>
12 12 <script lang="ts" setup>
13   - import { ref } from 'vue';
  13 + import { onMounted, ref } from 'vue';
14 14 import GrowCard from './components/GrowCard.vue';
15 15 import SiteAnalysis from './components/SiteAnalysis.vue';
16   - import VisitSource from './components/VisitSource.vue';
17   - import VisitRadar from './components/VisitRadar.vue';
18   - import SalesProductPie from './components/SalesProductPie.vue';
  16 + import { useDataStoreWithOut } from '/@/store/modules/data';
19 17  
20 18 const loading = ref(true);
  19 + const dataStore = useDataStoreWithOut();
  20 +
  21 + onMounted(() => {
  22 + dataStore.getFetchData();
  23 + dataStore.getFetchChartData();
  24 + });
21 25  
22 26 setTimeout(() => {
23 27 loading.value = false;
... ...
src/views/demo/permission/back/Btn.vue
... ... @@ -87,6 +87,7 @@
87 87 userStore.setToken(token);
88 88  
89 89 // 重新获取用户信息和菜单
  90 +
90 91 userStore.getUserInfoAction();
91 92 permissionStore.changePermissionCode();
92 93 }
... ...
src/views/demo/system/account/account.data.ts deleted 100644 → 0
1   -import { getAllRoleList, isAccountExist } from '/@/api/demo/system';
2   -import { BasicColumn, FormSchema } from '/@/components/Table';
3   -
4   -export const columns: BasicColumn[] = [
5   - {
6   - title: '用户名',
7   - dataIndex: 'account',
8   - width: 120,
9   - },
10   - {
11   - title: '昵称',
12   - dataIndex: 'nickname',
13   - width: 120,
14   - },
15   - {
16   - title: '邮箱',
17   - dataIndex: 'email',
18   - width: 120,
19   - },
20   - {
21   - title: '创建时间',
22   - dataIndex: 'createTime',
23   - width: 180,
24   - },
25   - {
26   - title: '角色',
27   - dataIndex: 'role',
28   - width: 200,
29   - },
30   - {
31   - title: '备注',
32   - dataIndex: 'remark',
33   - },
34   -];
35   -
36   -export const searchFormSchema: FormSchema[] = [
37   - {
38   - field: 'account',
39   - label: '用户名',
40   - component: 'Input',
41   - colProps: { span: 8 },
42   - },
43   - {
44   - field: 'nickname',
45   - label: '昵称',
46   - component: 'Input',
47   - colProps: { span: 8 },
48   - },
49   -];
50   -
51   -export const accountFormSchema: FormSchema[] = [
52   - {
53   - field: 'account',
54   - label: '用户名',
55   - component: 'Input',
56   - helpMessage: ['本字段演示异步验证', '不能输入带有admin的用户名'],
57   - rules: [
58   - {
59   - required: true,
60   - message: '请输入用户名',
61   - },
62   - {
63   - validator(_, value) {
64   - return new Promise((resolve, reject) => {
65   - isAccountExist(value)
66   - .then(() => resolve())
67   - .catch((err) => {
68   - reject(err.message || '验证失败');
69   - });
70   - });
71   - },
72   - },
73   - ],
74   - },
75   - {
76   - field: 'pwd',
77   - label: '密码',
78   - component: 'InputPassword',
79   - required: true,
80   - ifShow: false,
81   - },
82   - {
83   - label: '角色',
84   - field: 'role',
85   - component: 'ApiSelect',
86   - componentProps: {
87   - api: getAllRoleList,
88   - labelField: 'roleName',
89   - valueField: 'roleValue',
90   - },
91   - required: true,
92   - },
93   - {
94   - field: 'dept',
95   - label: '所属部门',
96   - component: 'TreeSelect',
97   - componentProps: {
98   - fieldNames: {
99   - label: 'deptName',
100   - key: 'id',
101   - value: 'id',
102   - },
103   - getPopupContainer: () => document.body,
104   - },
105   - required: true,
106   - },
107   - {
108   - field: 'nickname',
109   - label: '昵称',
110   - component: 'Input',
111   - required: true,
112   - },
113   -
114   - {
115   - label: '邮箱',
116   - field: 'email',
117   - component: 'Input',
118   - required: true,
119   - },
120   -
121   - {
122   - label: '备注',
123   - field: 'remark',
124   - component: 'InputTextArea',
125   - },
126   -];
src/views/demo/system/role/RoleDrawer.vue
... ... @@ -8,7 +8,7 @@
8 8 @ok="handleSubmit"
9 9 >
10 10 <BasicForm @register="registerForm">
11   - <template #menu="{ model, field }">
  11 + <!-- <template #menu="{ model, field }">
12 12 <BasicTree
13 13 v-model:value="model[field]"
14 14 :treeData="treeData"
... ... @@ -17,7 +17,7 @@
17 17 toolbar
18 18 title="菜单分配"
19 19 />
20   - </template>
  20 + </template> -->
21 21 </BasicForm>
22 22 </BasicDrawer>
23 23 </template>
... ...
src/views/demo/system/role/role.data.ts
... ... @@ -7,60 +7,60 @@ import { useMessage } from &#39;/@/hooks/web/useMessage&#39;;
7 7 export const columns: BasicColumn[] = [
8 8 {
9 9 title: '角色名称',
10   - dataIndex: 'roleName',
  10 + dataIndex: 'name',
11 11 width: 200,
12 12 },
13   - {
14   - title: '角色值',
15   - dataIndex: 'roleValue',
16   - width: 180,
17   - },
18   - {
19   - title: '排序',
20   - dataIndex: 'orderNo',
21   - width: 50,
22   - },
23   - {
24   - title: '状态',
25   - dataIndex: 'status',
26   - width: 120,
27   - customRender: ({ record }) => {
28   - if (!Reflect.has(record, 'pendingStatus')) {
29   - record.pendingStatus = false;
30   - }
31   - return h(Switch, {
32   - checked: record.status === '1',
33   - checkedChildren: '停用',
34   - unCheckedChildren: '启用',
35   - loading: record.pendingStatus,
36   - onChange(checked: boolean) {
37   - record.pendingStatus = true;
38   - const newStatus = checked ? '1' : '0';
39   - const { createMessage } = useMessage();
40   - setRoleStatus(record.id, newStatus)
41   - .then(() => {
42   - record.status = newStatus;
43   - createMessage.success(`已成功修改角色状态`);
44   - })
45   - .catch(() => {
46   - createMessage.error('修改角色状态失败');
47   - })
48   - .finally(() => {
49   - record.pendingStatus = false;
50   - });
51   - },
52   - });
53   - },
54   - },
  13 + // {
  14 + // title: '角色值',
  15 + // dataIndex: 'roleValue',
  16 + // width: 180,
  17 + // },
  18 + // {
  19 + // title: '排序',
  20 + // dataIndex: 'orderNo',
  21 + // width: 50,
  22 + // },
  23 + // {
  24 + // title: '状态',
  25 + // dataIndex: 'status',
  26 + // width: 120,
  27 + // customRender: ({ record }) => {
  28 + // if (!Reflect.has(record, 'pendingStatus')) {
  29 + // record.pendingStatus = false;
  30 + // }
  31 + // return h(Switch, {
  32 + // checked: record.status === '1',
  33 + // checkedChildren: '停用',
  34 + // unCheckedChildren: '启用',
  35 + // loading: record.pendingStatus,
  36 + // onChange(checked: boolean) {
  37 + // record.pendingStatus = true;
  38 + // const newStatus = checked ? '1' : '0';
  39 + // const { createMessage } = useMessage();
  40 + // setRoleStatus(record.id, newStatus)
  41 + // .then(() => {
  42 + // record.status = newStatus;
  43 + // createMessage.success(`已成功修改角色状态`);
  44 + // })
  45 + // .catch(() => {
  46 + // createMessage.error('修改角色状态失败');
  47 + // })
  48 + // .finally(() => {
  49 + // record.pendingStatus = false;
  50 + // });
  51 + // },
  52 + // });
  53 + // },
  54 + // },
55 55 {
56 56 title: '创建时间',
57 57 dataIndex: 'createTime',
58 58 width: 180,
59 59 },
60   - {
61   - title: '备注',
62   - dataIndex: 'remark',
63   - },
  60 + // {
  61 + // title: '备注',
  62 + // dataIndex: 'remark',
  63 + // },
64 64 ];
65 65  
66 66 export const searchFormSchema: FormSchema[] = [
... ...
src/views/demo/system/account/AccountDetail.vue renamed to src/views/project/account/AccountDetail.vue
src/views/demo/system/account/AccountModal.vue renamed to src/views/project/account/AccountModal.vue
... ... @@ -4,11 +4,10 @@
4 4 </BasicModal>
5 5 </template>
6 6 <script lang="ts">
7   - import { defineComponent, ref, computed, unref } from 'vue';
  7 + import { defineComponent, ref, computed, unref, toRaw } from 'vue';
8 8 import { BasicModal, useModalInner } from '/@/components/Modal';
9 9 import { BasicForm, useForm } from '/@/components/Form/index';
10 10 import { accountFormSchema } from './account.data';
11   - import { getDeptList } from '/@/api/demo/system';
12 11  
13 12 export default defineComponent({
14 13 name: 'AccountModal',
... ... @@ -18,7 +17,7 @@
18 17 const isUpdate = ref(true);
19 18 const rowId = ref('');
20 19  
21   - const [registerForm, { setFieldsValue, updateSchema, resetFields, validate }] = useForm({
  20 + const [registerForm, { setFieldsValue, resetFields, validate }] = useForm({
22 21 labelWidth: 100,
23 22 baseColProps: { span: 24 },
24 23 schemas: accountFormSchema,
... ... @@ -35,22 +34,11 @@
35 34  
36 35 if (unref(isUpdate)) {
37 36 rowId.value = data.record.id;
  37 +
38 38 setFieldsValue({
39   - ...data.record,
  39 + ...toRaw(data.record),
40 40 });
41 41 }
42   -
43   - const treeData = await getDeptList();
44   - updateSchema([
45   - {
46   - field: 'pwd',
47   - show: !unref(isUpdate),
48   - },
49   - {
50   - field: 'dept',
51   - componentProps: { treeData },
52   - },
53   - ]);
54 42 });
55 43  
56 44 const getTitle = computed(() => (!unref(isUpdate) ? '新增账号' : '编辑账号'));
... ... @@ -59,8 +47,7 @@
59 47 try {
60 48 const values = await validate();
61 49 setModalProps({ confirmLoading: true });
62   - // TODO custom api
63   - console.log(values);
  50 +
64 51 closeModal();
65 52 emit('success', { isUpdate: unref(isUpdate), values: { ...values, id: rowId.value } });
66 53 } finally {
... ...
src/views/demo/system/account/DeptTree.vue renamed to src/views/project/account/DeptTree.vue
src/views/project/account/account.data.ts 0 → 100644
  1 +import { getRoleList } from '/@/api/project/account';
  2 +
  3 +export const columns: BasicColumn[] = [
  4 + {
  5 + title: '手机号',
  6 + dataIndex: 'phone',
  7 + width: 120,
  8 + },
  9 + {
  10 + title: '昵称',
  11 + dataIndex: 'nickName',
  12 + width: 120,
  13 + },
  14 + // {
  15 + // title: '邮箱',
  16 + // dataIndex: 'email',
  17 + // width: 120,
  18 + // },
  19 + // {
  20 + // title: '创建时间',
  21 + // dataIndex: 'createTime',
  22 + // width: 180,
  23 + // },
  24 + {
  25 + title: '角色',
  26 + dataIndex: 'roleName',
  27 + width: 200,
  28 + },
  29 + {
  30 + title: '备注',
  31 + dataIndex: 'remark',
  32 + },
  33 +];
  34 +
  35 +export const searchFormSchema: FormSchema[] = [
  36 + {
  37 + field: 'phone',
  38 + label: '手机号',
  39 + component: 'Input',
  40 + colProps: { span: 8 },
  41 + },
  42 + {
  43 + field: 'nickName',
  44 + label: '昵称',
  45 + component: 'Input',
  46 + colProps: { span: 8 },
  47 + },
  48 +];
  49 +
  50 +export const accountFormSchema: FormSchema[] = [
  51 + {
  52 + field: 'phone',
  53 + label: '手机号',
  54 + component: 'Input',
  55 + // helpMessage: ['本字段演示异步验证', '不能输入带有admin的用户名'],
  56 + rules: [
  57 + {
  58 + required: true,
  59 + message: '请输入用户名',
  60 + },
  61 + // {
  62 + // validator(_, value) {
  63 + // return new Promise((resolve, reject) => {
  64 + // isAccountExist(value)
  65 + // .then(() => resolve())
  66 + // .catch((err) => {
  67 + // reject(err.message || '验证失败');
  68 + // });
  69 + // });
  70 + // },
  71 + // },
  72 + ],
  73 + },
  74 + // {
  75 + // field: 'pwd',
  76 + // label: '密码',
  77 + // component: 'InputPassword',
  78 + // required: true,
  79 + // ifShow: false,
  80 + // },
  81 + {
  82 + label: '角色',
  83 + field: 'roleName',
  84 + component: 'ApiSelect',
  85 + componentProps: {
  86 + api: getRoleList,
  87 + labelField: 'name',
  88 + valueField: 'level',
  89 + },
  90 + required: true,
  91 + },
  92 + // {
  93 + // field: 'dept',
  94 + // label: '所属部门',
  95 + // component: 'TreeSelect',
  96 + // componentProps: {
  97 + // fieldNames: {
  98 + // label: 'deptName',
  99 + // key: 'id',
  100 + // value: 'id',
  101 + // },
  102 + // getPopupContainer: () => document.body,
  103 + // },
  104 + // required: true,
  105 + // },
  106 + {
  107 + field: 'nickName',
  108 + label: '昵称',
  109 + component: 'Input',
  110 + required: true,
  111 + },
  112 +
  113 + // {
  114 + // label: '邮箱',
  115 + // field: 'email',
  116 + // component: 'Input',
  117 + // required: true,
  118 + // },
  119 +
  120 + {
  121 + label: '备注',
  122 + field: 'remark',
  123 + component: 'InputTextArea',
  124 + },
  125 +];
... ...
src/views/demo/system/account/index.vue renamed to src/views/project/account/index.vue
1 1 <template>
2 2 <PageWrapper dense contentFullHeight fixedHeight contentClass="flex">
3   - <DeptTree class="w-1/4 xl:w-1/5" @select="handleSelect" />
4   - <BasicTable @register="registerTable" class="w-3/4 xl:w-4/5" :searchInfo="searchInfo">
  3 + <!-- <DeptTree class="w-1/4 xl:w-1/5" @select="handleSelect" /> -->
  4 + <BasicTable @register="registerTable" :searchInfo="searchInfo">
5 5 <template #toolbar>
6 6 <a-button type="primary" @click="handleCreate">新增账号</a-button>
7 7 </template>
... ... @@ -9,11 +9,11 @@
9 9 <template v-if="column.key === 'action'">
10 10 <TableAction
11 11 :actions="[
12   - {
13   - icon: 'clarity:info-standard-line',
14   - tooltip: '查看用户详情',
15   - onClick: handleView.bind(null, record),
16   - },
  12 + // {
  13 + // icon: 'clarity:info-standard-line',
  14 + // tooltip: '查看用户详情',
  15 + // onClick: handleView.bind(null, record),
  16 + // },
17 17 {
18 18 icon: 'clarity:note-edit-line',
19 19 tooltip: '编辑用户资料',
... ... @@ -41,7 +41,7 @@
41 41 import { defineComponent, reactive } from 'vue';
42 42  
43 43 import { BasicTable, useTable, TableAction } from '/@/components/Table';
44   - import { getAccountList } from '/@/api/demo/system';
  44 + import { getUserList, userAdd, userEdit } from '/@/api/project/account';
45 45 import { PageWrapper } from '/@/components/Page';
46 46 import DeptTree from './DeptTree.vue';
47 47  
... ... @@ -57,10 +57,10 @@
57 57 setup() {
58 58 const go = useGo();
59 59 const [registerModal, { openModal }] = useModal();
60   - const searchInfo = reactive<Recordable>({});
  60 + const searchInfo = reactive({});
61 61 const [registerTable, { reload, updateTableDataRecord }] = useTable({
62 62 title: '账号列表',
63   - api: getAccountList,
  63 + api: getUserList,
64 64 rowKey: 'id',
65 65 columns,
66 66 formConfig: {
... ... @@ -101,15 +101,14 @@
101 101 console.log(record);
102 102 }
103 103  
104   - function handleSuccess({ isUpdate, values }) {
  104 + async function handleSuccess({ isUpdate, values }) {
105 105 if (isUpdate) {
106   - // 演示不刷新表格直接更新内部数据。
107   - // 注意:updateTableDataRecord要求表格的rowKey属性为string并且存在于每一行的record的keys中
108   - const result = updateTableDataRecord(values.id, values);
109   - console.log(result);
  106 + await userEdit({ ...values });
110 107 } else {
111   - reload();
  108 + await userAdd({ ...values });
112 109 }
  110 +
  111 + reload();
113 112 }
114 113  
115 114 function handleSelect(deptId = '') {
... ...
src/views/project/approve/index.vue 0 → 100644
  1 +<template>
  2 + <PageWrapper contentBackground>
  3 + <template #footer>
  4 + <a-tabs default-active-key="1" v-model:activeKey="currentKey">
  5 + <a-tab-pane key="1" tab="申请/待审核列表"
  6 + ><BasicTable @register="registerTable1">
  7 + <template #form-custom> custom-slot </template>
  8 + <template #bodyCell="{ column, record }">
  9 + <template v-if="column.key === 'action'">
  10 + <TableAction
  11 + :actions="[
  12 + {
  13 + label: '通过',
  14 + // icon: 'ic:outline-delete-outline',
  15 + onClick: handleTrue.bind(null, record),
  16 + },
  17 + {
  18 + label: '拒绝',
  19 + // icon: 'ic:outline-delete-outline',
  20 + onClick: handleFalse.bind(null, record),
  21 + },
  22 + ]"
  23 + />
  24 + </template>
  25 + </template> </BasicTable
  26 + ></a-tab-pane>
  27 + <a-tab-pane key="2" tab="已审核列表">
  28 + <BasicTable @register="registerTable2" />
  29 + </a-tab-pane>
  30 + </a-tabs>
  31 + </template>
  32 + </PageWrapper>
  33 +</template>
  34 +<script lang="ts">
  35 + import { defineComponent, ref } from 'vue';
  36 + import { BasicTable, useTable, TableAction } from '/@/components/Table';
  37 + import { Tabs } from 'ant-design-vue';
  38 + import { PageWrapper } from '/@/components/Page';
  39 +
  40 + import { approveAuditApi, getWaitListApi, getApprovedListApi } from '/@/api/project/approve';
  41 +
  42 + export default defineComponent({
  43 + components: {
  44 + PageWrapper,
  45 + BasicTable,
  46 + TableAction,
  47 + [Tabs.name]: Tabs,
  48 + [Tabs.TabPane.name]: Tabs.TabPane,
  49 + },
  50 + setup() {
  51 + const checkedKeys = ref<Array<string | number>>([]);
  52 + const currentKey = ref('1');
  53 +
  54 + const [registerTable1, { reload }] = useTable({
  55 + api: getWaitListApi,
  56 + columns: [
  57 + {
  58 + title: '申请人',
  59 + dataIndex: 'createBy',
  60 + width: 150,
  61 + },
  62 + {
  63 + title: '申请字段',
  64 + dataIndex: 'fields',
  65 + width: 600,
  66 + },
  67 + {
  68 + title: '订单号',
  69 + dataIndex: 'no6',
  70 + },
  71 + {
  72 + title: '订单字段1',
  73 + dataIndex: 'no5',
  74 + },
  75 + {
  76 + title: '订单字段2',
  77 + dataIndex: 'no4',
  78 + },
  79 + {
  80 + title: '订单字段3',
  81 + dataIndex: 'no3',
  82 + },
  83 +
  84 + {
  85 + title: '订单字段5',
  86 + dataIndex: 'no1',
  87 + },
  88 + ],
  89 + // useSearchForm: true,
  90 + // formConfig: getFormConfig(),
  91 + rowKey: 'id',
  92 + actionColumn: {
  93 + width: 160,
  94 + title: 'Action',
  95 + dataIndex: 'action',
  96 + // slots: { customRender: 'action' },
  97 + },
  98 + });
  99 +
  100 + const [registerTable2] = useTable({
  101 + api: getApprovedListApi,
  102 + columns: [
  103 + {
  104 + title: '申请人',
  105 + dataIndex: 'createBy',
  106 + width: 150,
  107 + },
  108 + {
  109 + title: '申请字段',
  110 + dataIndex: 'fields',
  111 + width: 600,
  112 + },
  113 + {
  114 + title: '订单号',
  115 + dataIndex: 'no6',
  116 + },
  117 + {
  118 + title: '订单字段1',
  119 + dataIndex: 'no5',
  120 + },
  121 + {
  122 + title: '订单字段2',
  123 + dataIndex: 'no4',
  124 + },
  125 + {
  126 + title: '订单字段3',
  127 + dataIndex: 'no3',
  128 + },
  129 +
  130 + {
  131 + title: '订单字段5',
  132 + dataIndex: 'no1',
  133 + },
  134 + ],
  135 + rowKey: 'id',
  136 + });
  137 +
  138 + // function getFormValues() {
  139 + // console.log(getForm1().getFieldsValue());
  140 + // }
  141 +
  142 + function onSelect(record, selected) {
  143 + if (selected) {
  144 + checkedKeys.value = [...checkedKeys.value, record.id];
  145 + } else {
  146 + checkedKeys.value = checkedKeys.value.filter((id) => id !== record.id);
  147 + }
  148 + }
  149 + function onSelectAll(selected, selectedRows, changeRows) {
  150 + const changeIds = changeRows.map((item) => item.id);
  151 + if (selected) {
  152 + checkedKeys.value = [...checkedKeys.value, ...changeIds];
  153 + } else {
  154 + checkedKeys.value = checkedKeys.value.filter((id) => {
  155 + return !changeIds.includes(id);
  156 + });
  157 + }
  158 + }
  159 + function handleEdit(record, e) {
  160 + e?.stopPropagation();
  161 + return false;
  162 + }
  163 +
  164 + function handleProfitModal() {}
  165 +
  166 + async function handleTrue(record) {
  167 + await approveAuditApi({ status: 10, id: record.id });
  168 + reload();
  169 + }
  170 +
  171 + async function handleFalse(record) {
  172 + await approveAuditApi({ status: 20, id: record.id });
  173 + reload();
  174 + }
  175 +
  176 + return {
  177 + handleProfitModal,
  178 + registerTable1,
  179 + registerTable2,
  180 + checkedKeys,
  181 + currentKey,
  182 + onSelect,
  183 + handleEdit,
  184 + onSelectAll,
  185 + handleTrue,
  186 + handleFalse,
  187 + };
  188 + },
  189 + });
  190 +</script>
... ...
src/views/project/order/CheckDetail.vue 0 → 100644
  1 +<template>
  2 + <BasicDrawer
  3 + @register="register"
  4 + v-bind="$attrs"
  5 + showFooter
  6 + title="字段编辑权限申请"
  7 + width="60%"
  8 + :isDetail="true"
  9 + @ok="handleSubmit"
  10 + :showDetailBack="false"
  11 + okText="申请"
  12 + ><input />
  13 + <div>
  14 + <h3>基本信息</h3>
  15 + <BasicForm @register="registerForm" />
  16 + <h3>利润分析</h3>
  17 + <BasicForm @register="registerProfitForm" />
  18 + </div>
  19 + <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> -->
  20 +
  21 + <template #appendFooter>
  22 + <a-button type="primary" @click="onGoFormDetail"> 返回编辑</a-button>
  23 + </template>
  24 + </BasicDrawer>
  25 +</template>
  26 +<script lang="ts">
  27 + import { defineComponent, reactive, ref } from 'vue';
  28 + import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
  29 + import { orderAuth } from '/@/api/project/order';
  30 +
  31 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  32 + import { FIELDS_BASE_INFO, FIELDS_PROFIT_INFO } from './tableData';
  33 + import { cloneDeep, isEmpty, mapValues, mergeWith } from 'lodash-es';
  34 +
  35 + const getSchema = (fields, base) =>
  36 + fields.map((item) => ({
  37 + field: `${base}.${item.field}`,
  38 + dataIndex: `${base}.${item.field}`,
  39 + label: item.label,
  40 + component: 'Switch',
  41 + colProps: {
  42 + span: 6,
  43 + },
  44 + }));
  45 +
  46 + export default defineComponent({
  47 + components: { BasicDrawer, BasicForm },
  48 + props: {
  49 + onGoFormDetail: {
  50 + type: Function,
  51 + },
  52 + },
  53 + setup() {
  54 + const id = ref('');
  55 + const schemas = getSchema(FIELDS_BASE_INFO, 'baseFields');
  56 + const profitSchemas = getSchema(FIELDS_PROFIT_INFO, 'profitAnalysisFields');
  57 + const [registerForm, { getFieldsValue }] = useForm({
  58 + labelWidth: 120,
  59 + schemas,
  60 + showActionButtonGroup: false,
  61 + actionColOptions: {
  62 + span: 24,
  63 + },
  64 + });
  65 + const [registerProfitForm, { getFieldsValue: getProfitFieldsValue }] = useForm({
  66 + labelWidth: 120,
  67 + schemas: profitSchemas,
  68 + showActionButtonGroup: false,
  69 + actionColOptions: {
  70 + span: 24,
  71 + },
  72 + });
  73 + const lockFields = reactive({});
  74 + const [register, { closeDrawer }] = useDrawerInner((data) => {
  75 + Object.assign(lockFields, data.lockFields);
  76 + id.value = data.id;
  77 + });
  78 +
  79 + function customizer(objValue, srcValue, key) {
  80 + // 检查是否在 baseFields 内以及值是否为 true
  81 + if (srcValue === true) {
  82 + return 'UN_LOCKED';
  83 + }
  84 + return objValue; // 如果不需要改变,返回原值
  85 + }
  86 + const handleSubmit = async () => {
  87 + const baseFieldValues = getFieldsValue();
  88 + const profitFieldValues = getProfitFieldsValue();
  89 +
  90 + !isEmpty(baseFieldValues) &&
  91 + Object.keys(baseFieldValues.baseFields)?.map((key) => {
  92 + baseFieldValues.baseFields[key] = baseFieldValues.baseFields[key]
  93 + ? 'UN_LOCKED'
  94 + : 'LOCKED';
  95 + });
  96 +
  97 + !isEmpty(profitFieldValues) &&
  98 + Object.keys(profitFieldValues.profitAnalysisFields).map((key) => {
  99 + profitFieldValues.profitAnalysisFields[key] = profitFieldValues.profitAnalysisFields[
  100 + key
  101 + ]
  102 + ? 'UN_LOCKED'
  103 + : 'LOCKED';
  104 + });
  105 +
  106 + const values = Object.assign({ orderId: id.value }, baseFieldValues, profitFieldValues);
  107 + console.log('%c [ values ]-103', 'font-size:13px; background:pink; color:#bf2c9f;', values);
  108 + await orderAuth(values);
  109 + closeDrawer();
  110 + };
  111 + return { register, schemas, registerForm, registerProfitForm, handleSubmit };
  112 + },
  113 + });
  114 +</script>
... ...
src/views/project/order/FieldDetail.vue 0 → 100644
  1 +<template>
  2 + <BasicDrawer
  3 + @register="register"
  4 + v-bind="$attrs"
  5 + title="title"
  6 + width="60%"
  7 + :isDetail="true"
  8 + :showDetailBack="false"
  9 + >
  10 + <div>
  11 + <BasicTable @register="registerTable" @edit-change="handleEditChange">
  12 + <template #bodyCell="{ column, record }">
  13 + <template v-if="column.key === 'action'">
  14 + <TableAction :actions="createActions(record, column)" />
  15 + </template>
  16 + </template>
  17 + </BasicTable>
  18 + <a-button block class="mt-5" type="dashed" @click="handleAdd"> 新增选项 </a-button>
  19 + </div>
  20 + <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> -->
  21 + </BasicDrawer>
  22 +</template>
  23 +<script lang="ts">
  24 + import { defineComponent, ref, toRaw } from 'vue';
  25 + import {
  26 + BasicTable,
  27 + useTable,
  28 + TableAction,
  29 + BasicColumn,
  30 + ActionItem,
  31 + EditRecordRow,
  32 + } from '/@/components/Table';
  33 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  34 + import { useOrderStoreWithOut } from '/@/store/modules/order';
  35 + import { dictCreate, dictDelete, dictList, dictUpdate } from '/@/api/project/order';
  36 +
  37 + const orderStore = useOrderStoreWithOut();
  38 +
  39 + const columns: BasicColumn[] = [
  40 + {
  41 + title: '筛选项',
  42 + dataIndex: 'dictValue',
  43 + editRow: true,
  44 + },
  45 + ];
  46 +
  47 + export default defineComponent({
  48 + components: { BasicDrawer, BasicTable, TableAction },
  49 + props: {
  50 + onGoFormDetail: {
  51 + type: Function,
  52 + },
  53 + },
  54 + setup() {
  55 + const dataSource = ref([]);
  56 + const key = ref('');
  57 + const title = ref('');
  58 +
  59 + const [registerTable, { getDataSource, reload }] = useTable({
  60 + columns: columns,
  61 + showIndexColumn: false,
  62 + dataSource: toRaw(dataSource),
  63 + actionColumn: {
  64 + width: 160,
  65 + title: '操作',
  66 + dataIndex: 'action',
  67 + // slots: { customRender: 'action' },
  68 + },
  69 + scroll: { y: '100%' },
  70 + pagination: false,
  71 + });
  72 +
  73 + const [register] = useDrawerInner((data) => {
  74 + const { dataIndex, customTitle } = data;
  75 + const dicts = orderStore.getDictInfo;
  76 + const dict = dicts[dataIndex];
  77 + dataSource.value = dict;
  78 + title.value = customTitle;
  79 + key.value = dataIndex;
  80 + });
  81 +
  82 + function handleEdit(record: EditRecordRow) {
  83 + record.onEdit?.(true);
  84 + }
  85 +
  86 + function handleCancel(record: EditRecordRow) {
  87 + record.onEdit?.(false);
  88 + if (record.isNew) {
  89 + const data = getDataSource();
  90 + const index = data.findIndex((item) => item.key === record.key);
  91 + data.splice(index, 1);
  92 + }
  93 + }
  94 +
  95 + async function handleSave(record: EditRecordRow) {
  96 + if (record.id) {
  97 + await dictUpdate({ dictCode: key.value, dictValue: record.dictValue });
  98 + } else {
  99 + await dictCreate({
  100 + dictName: title.value,
  101 + dictCode: key.value,
  102 + dictValue: record.dictValue,
  103 + sort: dataSource.value.length + 1,
  104 + });
  105 + }
  106 +
  107 + await orderStore.getDict();
  108 +
  109 + setTimeout(async () => {
  110 + const res = await dictList({ dictCode: key.value });
  111 + dataSource.value = res.records;
  112 + reload();
  113 + }, 300);
  114 + }
  115 +
  116 + async function handleDelete(record) {
  117 + await dictDelete({ ids: [record.id] });
  118 + await orderStore.getDict();
  119 + record.onEdit?.(false, true);
  120 + setTimeout(async () => {
  121 + const res = await dictList({ dictCode: key.value });
  122 + dataSource.value = res.records;
  123 + reload();
  124 + }, 300);
  125 + }
  126 +
  127 + function handleEditChange(data) {
  128 + console.log(data);
  129 + }
  130 +
  131 + function handleAdd() {
  132 + const data = getDataSource();
  133 + const addRow: EditRecordRow = {
  134 + name: '',
  135 + no: '',
  136 + dept: '',
  137 + editable: true,
  138 + isNew: true,
  139 + key: `${Date.now()}`,
  140 + };
  141 + data.push(addRow);
  142 + }
  143 +
  144 + function createActions(record: EditRecordRow, column: BasicColumn): ActionItem[] {
  145 + if (!record.editable) {
  146 + return [
  147 + {
  148 + label: '编辑',
  149 + onClick: handleEdit.bind(null, record),
  150 + },
  151 + {
  152 + label: '删除',
  153 + onClick: handleDelete.bind(null, record),
  154 + },
  155 + ];
  156 + }
  157 + return [
  158 + {
  159 + label: '保存',
  160 + onClick: handleSave.bind(null, record, column),
  161 + },
  162 + {
  163 + label: '取消',
  164 + popConfirm: {
  165 + title: '是否取消编辑',
  166 + confirm: handleCancel.bind(null, record, column),
  167 + },
  168 + },
  169 + ];
  170 + }
  171 + return {
  172 + title,
  173 + register,
  174 + registerTable,
  175 + handleEdit,
  176 + createActions,
  177 + handleAdd,
  178 + getDataSource,
  179 + handleEditChange,
  180 + };
  181 + },
  182 + });
  183 +</script>
... ...
src/views/project/order/FormDetail.vue 0 → 100644
  1 +<template>
  2 + <BasicDrawer
  3 + v-bind="$attrs"
  4 + showFooter
  5 + @register="register"
  6 + @ok="handleSubmit"
  7 + title=""
  8 + width="28%"
  9 + ref="formRef"
  10 + :isDetail="true"
  11 + :showDetailBack="false"
  12 + okText="保存"
  13 + :mask="false"
  14 + class="z-20"
  15 + >
  16 + <Tabs v-model:activeKey="activeKey">
  17 + <TabPanel key="1" tab="基本信息" :forceRender="true">
  18 + <BasicForm @register="registerForm" />
  19 + </TabPanel>
  20 + <TabPanel key="2" tab="利润分析" :forceRender="true">
  21 + <ProfitFormPanel ref="profitFormPanelRef" :id="id" />
  22 + </TabPanel>
  23 + <TabPanel key="3" tab="项目报告书" :forceRender="true">
  24 + <ReportFormPanel ref="ReportFormPanelRef" />
  25 + </TabPanel>
  26 + <TabPanel key="4" tab="跟单信息" :forceRender="true">
  27 + <TrackFormPanel ref="TrackFormPanelRef" />
  28 + </TabPanel>
  29 + <TabPanel key="5" tab="质检信息" :forceRender="true">
  30 + <InspectionFormPanel ref="InspectionFormRef" />
  31 + </TabPanel>
  32 + </Tabs>
  33 + <!-- <BasicForm @register="registerForm" />
  34 + <BasicForm @register="registerForm" />
  35 + <BasicForm @register="registerForm" /> -->
  36 + <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> -->
  37 +
  38 + <!-- <template #appendFooter>
  39 + <a-button type="primary" @click="onGoCheckDetail"> 申请权限</a-button>
  40 + </template> -->
  41 + </BasicDrawer>
  42 +</template>
  43 +<script lang="ts">
  44 + import { computed, defineComponent, reactive, ref, toRaw, watch, watchEffect } from 'vue';
  45 + import { BasicForm, FormActionType, FormSchema, useForm } from '/@/components/Form/index';
  46 + import { orderCreate, orderUpdate, uploadImg } from '/@/api/project/order';
  47 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  48 + import { useOrderStoreWithOut } from '/@/store/modules/order';
  49 + import { useOrderInfo } from '/@/hooks/component/order';
  50 + import { dateUtil } from '/@/utils/dateUtil';
  51 + import { FIELDS_REPORT_INFO } from './tableData';
  52 + import ProfitFormPanel from './component/ProfitFormPanel.vue';
  53 + import ReportFormPanel from './component/ReportFormPanel.vue';
  54 + import TrackFormPanel from './component/TrackFormPanel.vue';
  55 + import InspectionFormPanel from './component/InspectionFormPanel.vue';
  56 +
  57 + import { Tabs } from 'ant-design-vue';
  58 +
  59 + const TabPanel = Tabs.TabPane;
  60 +
  61 + export default defineComponent({
  62 + components: {
  63 + BasicDrawer,
  64 + BasicForm,
  65 + Tabs,
  66 + TabPanel,
  67 + ProfitFormPanel,
  68 + ReportFormPanel,
  69 + TrackFormPanel,
  70 + InspectionFormPanel,
  71 + },
  72 +
  73 + props: {
  74 + detailData: {
  75 + type: Object,
  76 + },
  77 + onGoCheckDetail: {
  78 + type: Function,
  79 + },
  80 + },
  81 + emits: ['success'],
  82 + setup(_, { emit }) {
  83 + const orderStore = useOrderStoreWithOut();
  84 + const activeKey = ref('1');
  85 + const profitFormPanelRef = ref(null);
  86 + const ReportFormPanelRef = ref(null);
  87 + const TrackFormPanelRef = ref(null);
  88 + const InspectionFormPanelRef = ref(null);
  89 +
  90 + const {
  91 + customerCode,
  92 + projectNo,
  93 + productionDepartment,
  94 + innerNo,
  95 + poColor,
  96 + cnColor,
  97 + productStyle,
  98 + outboundType,
  99 + packetType,
  100 + } = useOrderInfo(orderStore);
  101 +
  102 + const formRef = ref<FormActionType | null>(null);
  103 + const id = ref('');
  104 +
  105 + // const customerCode = computed(() => {
  106 + // const dictInfo = orderStore.getDictInfo;
  107 + // return map(dictInfo?.customerCode, transformDictInfo);
  108 + // });
  109 +
  110 + // const projectNo = computed(() => {
  111 + // const dictInfo = orderStore.getDictInfo;
  112 + // return map(dictInfo?.projectNo, transformDictInfo);
  113 + // });
  114 +
  115 + const picUrl = ref('');
  116 + let fields = reactive({ baseFields: {} });
  117 + const getDisable = (code) => {
  118 + return code === 'LOCKED' && !!id.value;
  119 + };
  120 +
  121 + const schemas = computed(() => {
  122 + return [
  123 + {
  124 + field: 'baseInfo.customerCode',
  125 + component: 'Select',
  126 + label: '客户编码',
  127 + rules: [{ required: true }],
  128 + colProps: {
  129 + span: 24,
  130 + },
  131 + componentProps: {
  132 + options: customerCode,
  133 + disabled: getDisable(fields?.baseFields.customerCode),
  134 + },
  135 + },
  136 + {
  137 + field: 'baseInfo.projectNo',
  138 + component: 'Select',
  139 + componentProps: {
  140 + options: projectNo,
  141 + disabled: getDisable(fields?.baseFields?.projectNo),
  142 + },
  143 + label: '项目号',
  144 + rules: [{ required: true }],
  145 + colProps: {
  146 + span: 24,
  147 + },
  148 + },
  149 + {
  150 + field: 'baseInfo.productionDepartment',
  151 + component: 'Select',
  152 + label: '生产科',
  153 + rules: [{ required: true }],
  154 + colProps: {
  155 + span: 24,
  156 + },
  157 + componentProps: {
  158 + options: productionDepartment,
  159 + disabled: getDisable(fields?.baseFields?.productionDepartment),
  160 + },
  161 + },
  162 + {
  163 + field: 'baseInfo.innerNo',
  164 + component: 'Select',
  165 + label: '内部编号',
  166 + rules: [{ required: true }],
  167 +
  168 + colProps: {
  169 + span: 24,
  170 + },
  171 + componentProps: {
  172 + options: innerNo,
  173 + disabled: getDisable(fields?.baseFields?.innerNo),
  174 + },
  175 + },
  176 + {
  177 + field: 'baseInfo.customerPo',
  178 + component: 'Input',
  179 + label: '客户po号',
  180 + rules: [{ required: true }],
  181 + componentProps: {
  182 + disabled: getDisable(fields?.baseFields?.customerPo),
  183 + },
  184 + colProps: {
  185 + span: 24,
  186 + },
  187 + },
  188 + {
  189 + field: 'baseInfo.customerStyle',
  190 + component: 'Input',
  191 + label: '客户STYLE',
  192 + rules: [{ required: true }],
  193 +
  194 + colProps: {
  195 + span: 24,
  196 + },
  197 + componentProps: {
  198 + disabled: getDisable(fields?.baseFields?.customerStyle),
  199 + },
  200 + },
  201 + {
  202 + field: 'baseInfo.collection',
  203 + component: 'Input',
  204 + label: 'COLLECTION (style description)',
  205 + rules: [{ required: true }],
  206 +
  207 + colProps: {
  208 + span: 24,
  209 + },
  210 + componentProps: {
  211 + disabled: getDisable(fields?.baseFields?.collection),
  212 + },
  213 + },
  214 + {
  215 + field: 'baseInfo.poColor',
  216 + component: 'Select',
  217 + label: 'PO COLOR',
  218 + rules: [{ required: true }],
  219 +
  220 + colProps: {
  221 + span: 24,
  222 + },
  223 + componentProps: {
  224 + options: poColor,
  225 + disabled: getDisable(fields?.baseFields?.poColor),
  226 + },
  227 + },
  228 + {
  229 + field: 'baseInfo.cnColor',
  230 + component: 'Select',
  231 + label: '颜色中文',
  232 + rules: [{ required: true }],
  233 +
  234 + colProps: {
  235 + span: 24,
  236 + },
  237 + componentProps: {
  238 + options: cnColor,
  239 + disabled: getDisable(fields?.baseFields?.cnColor),
  240 + },
  241 + },
  242 + {
  243 + field: 'baseInfo.picUrl',
  244 + component: 'FieldUpload',
  245 + label: '图片',
  246 + rules: [{ required: true }],
  247 + colProps: {
  248 + span: 24,
  249 + },
  250 + componentProps: {
  251 + imgUrl: picUrl,
  252 + disabled: getDisable(fields?.baseFields?.picUrl),
  253 + onChange: (res) => {
  254 + if (res.file?.response?.data) picUrl.value = res.file?.response?.data;
  255 + },
  256 + },
  257 + },
  258 + {
  259 + field: 'baseInfo.productionComment',
  260 + component: 'Input',
  261 + rules: [{ required: true }],
  262 + label: '生产要求',
  263 + componentProps: {
  264 + disabled: getDisable(fields?.baseFields?.productionComment),
  265 + },
  266 + colProps: {
  267 + span: 24,
  268 + },
  269 + },
  270 + {
  271 + field: 'baseInfo.orderCount',
  272 + component: 'InputNumber',
  273 + rules: [{ required: true }],
  274 + label: '数量',
  275 + colProps: {
  276 + span: 24,
  277 + },
  278 + componentProps: {
  279 + disabled: getDisable(fields?.baseFields?.orderCount),
  280 + },
  281 + },
  282 + {
  283 + field: 'baseInfo.orderComposition',
  284 + component: 'Input',
  285 + rules: [{ required: true }],
  286 + label: '订单成分',
  287 + colProps: {
  288 + span: 24,
  289 + },
  290 + componentProps: {
  291 + disabled: getDisable(fields?.baseFields?.orderComposition),
  292 + },
  293 + },
  294 + {
  295 + field: 'baseInfo.productStyle',
  296 + component: 'Select',
  297 + rules: [{ required: true }],
  298 + label: '款式类型',
  299 + colProps: {
  300 + span: 24,
  301 + },
  302 + componentProps: {
  303 + options: productStyle,
  304 + disabled: getDisable(fields?.baseFields?.productStyle),
  305 + },
  306 + },
  307 + {
  308 + field: 'baseInfo.productionDepartmentConsignTime',
  309 + component: 'DatePicker',
  310 + label: '生成科拖货时间',
  311 + colProps: {
  312 + span: 24,
  313 + },
  314 + componentProps: {
  315 + disabled: getDisable(fields?.baseFields?.productionDepartmentConsignTime),
  316 + },
  317 + rules: [{ required: true }],
  318 + },
  319 + {
  320 + field: 'baseInfo.orderHodTime',
  321 + component: 'DatePicker',
  322 + label: '订单上HOD时间',
  323 + colProps: {
  324 + span: 24,
  325 + },
  326 + componentProps: {
  327 + disabled: getDisable(fields?.baseFields?.orderHodTime),
  328 + },
  329 + rules: [{ required: true }],
  330 + },
  331 + {
  332 + field: 'baseInfo.outboundType',
  333 + component: 'Select',
  334 + label: '出库类型',
  335 + colProps: {
  336 + span: 24,
  337 + },
  338 + rules: [{ required: true }],
  339 + componentProps: {
  340 + disabled: getDisable(fields?.baseFields?.outboundType),
  341 + options: outboundType,
  342 + },
  343 + },
  344 + {
  345 + field: 'baseInfo.packetType',
  346 + component: 'Select',
  347 + label: '包装类型',
  348 + colProps: {
  349 + span: 24,
  350 + },
  351 + rules: [{ required: true }],
  352 + componentProps: {
  353 + options: packetType,
  354 + disabled: getDisable(fields?.baseFields?.packetType),
  355 + },
  356 + },
  357 + ];
  358 + });
  359 + const reportSchemas = computed(() => {
  360 + return FIELDS_REPORT_INFO.map((item) => {
  361 + return {
  362 + field: `reportInfo.${item.field}`,
  363 + component: item.component,
  364 + label: item.label,
  365 + rules: [{ required: true }],
  366 + colProps: {
  367 + span: 24,
  368 + },
  369 + componentProps: {
  370 + disabled: getDisable(fields?.baseFields.customerCode),
  371 + },
  372 + };
  373 + });
  374 + });
  375 +
  376 + const [registerForm, { setFieldsValue, getFieldsValue, reload }] = useForm({
  377 + labelWidth: 120,
  378 + schemas,
  379 + showActionButtonGroup: false,
  380 + actionColOptions: {
  381 + span: 24,
  382 + },
  383 + });
  384 +
  385 + const [register, { closeDrawer }] = useDrawerInner((data) => {
  386 + id.value = data.id;
  387 +
  388 + // 方式1
  389 + picUrl.value = data.picUrl;
  390 + data.orderHodTime = data.orderHodTime ? dateUtil(data.orderHodTime) : null;
  391 + data.productionDepartmentConsignTime = data.productionDepartmentConsignTime
  392 + ? dateUtil(data.productionDepartmentConsignTime)
  393 + : null;
  394 +
  395 + fields.baseFields = {
  396 + ...fields.baseFields,
  397 + ...data.lockFields.baseFields,
  398 + };
  399 +
  400 + if (id.value) {
  401 + setFieldsValue({
  402 + baseInfo: { ...toRaw(data) },
  403 + });
  404 +
  405 + profitFormPanelRef.value.fields.profitAnalysisInfo =
  406 + { ...data.lockFields?.profitAnalysisFields } || {};
  407 +
  408 + profitFormPanelRef?.value?.setFieldsValue({
  409 + ...toRaw(data.profitAnalysisInfo),
  410 + profitAnalysisInfo: { ...toRaw(data.profitAnalysisInfo) },
  411 + });
  412 + } else {
  413 + setFieldsValue({});
  414 + }
  415 + });
  416 +
  417 + const handleSubmit = async () => {
  418 + const values = getFieldsValue() || {};
  419 +
  420 + values.baseInfo = {
  421 + ...values.baseInfo,
  422 + picUrl: picUrl?.value || '',
  423 + };
  424 + if (id.value) {
  425 + values.orderId = id.value;
  426 +
  427 + await orderUpdate(values);
  428 + } else {
  429 + const v2 = profitFormPanelRef?.value?.getFieldsValue() || { profitAnalysisInfo: {} };
  430 + const v3 = ReportFormPanelRef?.value?.getFieldsValue() || { reportInfo: {} };
  431 + const v4 = TrackFormPanelRef?.value?.getFieldsValue() || { trackStageInfo: {} };
  432 + const v5 = InspectionFormPanelRef?.value?.getFieldsValue() || { inspectionStageInfo: {} };
  433 +
  434 + values.profitAnalysisInfo = { ...v2.profitAnalysisInfo };
  435 + values.reportInfo = { ...v3.reportInfo };
  436 + values.trackStageInfo = { ...v4.trackStageInfo };
  437 + values.inspectionStageInfo = { ...v5.inspectionStageInfo };
  438 + await orderCreate(values);
  439 + }
  440 + closeDrawer();
  441 + emit('success', {});
  442 + };
  443 + return {
  444 + id,
  445 + profitFormPanelRef,
  446 + ReportFormPanelRef,
  447 + TrackFormPanelRef,
  448 + InspectionFormPanelRef,
  449 + activeKey,
  450 + formRef,
  451 + schemas,
  452 + register,
  453 + registerForm,
  454 + handleSubmit,
  455 + };
  456 + },
  457 + });
  458 +</script>
  459 +
  460 +<style>
  461 + .ant-drawer {
  462 + position: fixed;
  463 + z-index: 9999;
  464 + }
  465 +</style>
... ...
src/views/project/order/HistoryDetail.vue 0 → 100644
  1 +<template>
  2 + <BasicDrawer
  3 + v-bind="$attrs"
  4 + title="操作记录"
  5 + width="60%"
  6 + :isDetail="true"
  7 + :showDetailBack="false"
  8 + okText="保存"
  9 + >
  10 + <Tabs animated>
  11 + <template v-for="i in achieveList" :key="i.key">
  12 + <TabPane :tab="i.name" />
  13 + </template>
  14 + </Tabs>
  15 + <PageWrapper class="prefixCls">
  16 + <a-list :pagination="pagination" style="width: 100%">
  17 + <template v-for="item in list" :key="item.id">
  18 + <a-list-item class="list">
  19 + <a-list-item-meta>
  20 + <template #avatar>
  21 + <!-- <Icon class="icon" v-if="item.icon" :icon="item.icon" :color="item.color" /> -->
  22 + </template>
  23 + <template #title>
  24 + <!-- <span>{{ item.title }}</span> -->
  25 + <span>操作人</span>
  26 + <!-- <div class="extra" v-if="item.extra">
  27 + {{ item.extra }}
  28 + </div> -->
  29 + </template>
  30 + <template #description>
  31 + <div class="description">
  32 + <!-- {{ item.description }} -->
  33 + 干了什么
  34 + </div>
  35 + <div class="info">
  36 + <div><span>操作时间</span>{{ item.datetime }}</div>
  37 + </div>
  38 + </template>
  39 + </a-list-item-meta>
  40 + </a-list-item>
  41 + </template>
  42 + </a-list>
  43 + </PageWrapper>
  44 + <!-- <template #titleToolbar> <a-button type="primary"> 申请编辑权限 </a-button></template> -->
  45 +
  46 + <template #appendFooter>
  47 + <!-- <a-button type="primary" @click="onGoCheckDetail"> 申请权限</a-button> -->
  48 + </template>
  49 + </BasicDrawer>
  50 +</template>
  51 +<script lang="ts">
  52 + import { defineComponent } from 'vue';
  53 + import { Tabs, Progress, Row, Col, List } from 'ant-design-vue';
  54 + import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
  55 + import { cardList } from './data';
  56 + import { PageWrapper } from '/@/components/Page';
  57 +
  58 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  59 +
  60 + const schemas: FormSchema[] = [
  61 + {
  62 + field: '订单号',
  63 + component: 'Input',
  64 + label: '字段1',
  65 + componentProps: {
  66 + readonly: true,
  67 + disabled: true,
  68 + },
  69 + colProps: {
  70 + span: 12,
  71 + },
  72 + defaultValue: '111',
  73 + },
  74 + {
  75 + field: 'field2',
  76 + component: 'Input',
  77 + label: '字段2',
  78 + colProps: {
  79 + span: 12,
  80 + },
  81 + },
  82 + ];
  83 + const achieveList = [
  84 + {
  85 + key: '1',
  86 + name: '编辑记录',
  87 + },
  88 + {
  89 + key: '2',
  90 + name: '审批记录',
  91 + },
  92 + ];
  93 + export default defineComponent({
  94 + components: {
  95 + BasicDrawer,
  96 + Tabs,
  97 + [List.name]: List,
  98 + [List.Item.name]: List.Item,
  99 + AListItemMeta: List.Item.Meta,
  100 + PageWrapper,
  101 + },
  102 + props: {
  103 + onGoCheckDetail: {
  104 + type: Function,
  105 + },
  106 + },
  107 + setup() {
  108 + const [registerForm, { setFieldsValue }] = useForm({
  109 + labelWidth: 120,
  110 + schemas,
  111 + showActionButtonGroup: false,
  112 + actionColOptions: {
  113 + span: 24,
  114 + },
  115 + });
  116 + const [register] = useDrawerInner((data) => {
  117 + // 方式1
  118 + setFieldsValue({
  119 + field2: data.data,
  120 + field1: data.info,
  121 + });
  122 + });
  123 + return {
  124 + register,
  125 + schemas,
  126 + registerForm,
  127 + achieveList,
  128 + list: cardList,
  129 + prefixCls: 'account-center',
  130 +
  131 + pagination: {
  132 + show: true,
  133 + pageSize: 3,
  134 + },
  135 + };
  136 + },
  137 + });
  138 +</script>
  139 +
  140 +<style lang="less" scoped>
  141 + .account-center {
  142 + &-bottom {
  143 + margin: 0 16px 16px;
  144 + padding: 10px;
  145 + border-radius: 3px;
  146 + background-color: @component-background;
  147 + }
  148 + }
  149 +</style>
... ...
src/views/project/order/ProfitAnalysis.vue 0 → 100644
  1 +<template>
  2 + <BasicModal
  3 + v-bind="$attrs"
  4 + destroyOnClose
  5 + @register="register"
  6 + title="利润分析表"
  7 + :helpMessage="['提示1', '提示2']"
  8 + @visible-change="handleShow"
  9 + :footer="null"
  10 + >
  11 + <!-- <template #insertFooter>
  12 + <a-button type="primary" danger @click="setLines" :disabled="loading">点我更新内容</a-button>
  13 + </template> -->
  14 + <!-- <template v-if="loading">
  15 + <div class="empty-tips">加载中,稍等3秒……</div>
  16 + </template> -->
  17 + <Description
  18 + class="mt-4"
  19 + layout="vertical"
  20 + :collapseOptions="{ canExpand: true, helpMessage: 'help me' }"
  21 + :column="2"
  22 + :data="mockData"
  23 + :schema="schema"
  24 + />
  25 + </BasicModal>
  26 +</template>
  27 +<script lang="ts">
  28 + import { defineComponent, ref, toRaw, watch } from 'vue';
  29 + import { BasicModal, useModalInner } from '/@/components/Modal';
  30 + import { Description, DescItem, useDescription } from '/@/components/Description/index';
  31 + import { orderAnalysis } from '/@/api/project/order';
  32 +
  33 + export default defineComponent({
  34 + components: { BasicModal, Description },
  35 + setup() {
  36 + const loading = ref(true);
  37 + const lines = ref(10);
  38 + const [register, { setModalProps, redoModalHeight }] = useModalInner(async (data) => {
  39 + const orderIds = toRaw(data.data);
  40 + const res = await orderAnalysis({ orderIds });
  41 + });
  42 + const mockData = {
  43 + username: '100',
  44 + nickName: '100',
  45 + age: '123',
  46 + phone: '1222',
  47 + addr: '2332',
  48 + };
  49 +
  50 + const schema: DescItem[] = [
  51 + {
  52 + field: 'username',
  53 + label: '客户总金额',
  54 + },
  55 + {
  56 + field: 'nickName',
  57 + label: '供应商总价',
  58 + },
  59 + {
  60 + field: 'phone',
  61 + label: '包装费用',
  62 + },
  63 + {
  64 + field: 'addr',
  65 + label: '总利润率',
  66 + },
  67 + ];
  68 +
  69 + watch(
  70 + () => lines.value,
  71 + () => {
  72 + redoModalHeight();
  73 + },
  74 + );
  75 +
  76 + function handleShow(visible: boolean) {
  77 + if (visible) {
  78 + loading.value = true;
  79 + // setModalProps({ loading: true, confirmLoading: true });
  80 + setTimeout(() => {
  81 + lines.value = Math.round(Math.random() * 30 + 5);
  82 + loading.value = false;
  83 + setModalProps({ loading: false, confirmLoading: false });
  84 + }, 3000);
  85 + }
  86 + }
  87 +
  88 + function setLines() {
  89 + lines.value = Math.round(Math.random() * 20 + 10);
  90 + }
  91 + return { register, loading, handleShow, lines, setLines, mockData, schema };
  92 + },
  93 + });
  94 +</script>
  95 +<style scoped>
  96 + .empty-tips {
  97 + height: 100px;
  98 + line-height: 100px;
  99 + text-align: center;
  100 + }
  101 +</style>
... ...
src/views/project/order/component/InspectionFormPanel.vue 0 → 100644
  1 +<template>
  2 + <BasicForm @register="registerForm" />
  3 +</template>
  4 +<script lang="ts">
  5 + import { computed, defineComponent, reactive, ref, toRaw } from 'vue';
  6 + import { BasicForm, FormActionType, useForm } from '/@/components/Form/index';
  7 + import { useDrawerInner } from '/@/components/Drawer';
  8 + import { dateUtil } from '/@/utils/dateUtil';
  9 + import { FIELDS_INSPECTION_INFO } from '../tableData';
  10 + import { getDisable } from '/@/utils/project';
  11 + import { useOrderStoreWithOut } from '/@/store/modules/order';
  12 +
  13 + import { useOrderInfo } from '/@/hooks/component/order';
  14 +
  15 + export default defineComponent({
  16 + components: { BasicForm },
  17 +
  18 + props: {
  19 + detailData: {
  20 + type: Object,
  21 + },
  22 + onGoCheckDetail: {
  23 + type: Function,
  24 + },
  25 + },
  26 + emits: ['success'],
  27 + setup(_, { emit }) {
  28 + let fields = reactive({ baseFields: {}, profitAnalysisInfo: {} });
  29 + const orderStore = useOrderStoreWithOut();
  30 +
  31 + const { midCheckResult, endCheckResult } = useOrderInfo(orderStore);
  32 +
  33 + const schemas = computed(() => {
  34 + const options = {
  35 + midCheckResult,
  36 + endCheckResult,
  37 + };
  38 + return FIELDS_INSPECTION_INFO.map((item) => ({
  39 + ...item,
  40 + componentProps: {
  41 + ...(item.component === 'Select' && { options: options[item.optionField] }),
  42 + disabled: getDisable(`fields.${item.field}`),
  43 + },
  44 + colProps: {
  45 + span: 24,
  46 + },
  47 + }));
  48 + });
  49 +
  50 + const [registerForm, { setFieldsValue, getFieldsValue, reload }] = useForm({
  51 + labelWidth: 120,
  52 + schemas,
  53 + showActionButtonGroup: false,
  54 + actionColOptions: {
  55 + span: 24,
  56 + },
  57 + });
  58 +
  59 + const [register, { closeDrawer }] = useDrawerInner((data) => {
  60 + // 方式1
  61 + data.orderHodTime = data.orderHodTime ? dateUtil(data.orderHodTime) : null;
  62 + data.productionDepartmentConsignTime = data.productionDepartmentConsignTime
  63 + ? dateUtil(data.productionDepartmentConsignTime)
  64 + : null;
  65 +
  66 + fields.baseFields = {
  67 + ...fields.baseFields,
  68 + ...data.lockFields.baseFields,
  69 + };
  70 +
  71 + if (id.value) {
  72 + setFieldsValue({
  73 + ...toRaw(data),
  74 + baseInfo: { ...toRaw(data) },
  75 + });
  76 + } else {
  77 + setFieldsValue({});
  78 + }
  79 + });
  80 +
  81 + return { register, schemas, registerForm, getFieldsValue };
  82 + },
  83 + });
  84 +</script>
... ...
src/views/project/order/component/ProfitFormPanel.vue 0 → 100644
  1 +<template>
  2 + <BasicForm @register="registerForm" />
  3 +</template>
  4 +<script lang="ts">
  5 + import { computed, defineComponent, reactive, ref, toRaw } from 'vue';
  6 + import { BasicForm, FormActionType, useForm } from '/@/components/Form/index';
  7 + import { orderCreate, orderUpdate } from '/@/api/project/order';
  8 + import { dateUtil } from '/@/utils/dateUtil';
  9 + import { FIELDS_PROFIT_INFO } from '../tableData';
  10 + import { getDisable } from '/@/utils/project';
  11 + import { get } from 'lodash-es';
  12 +
  13 + export default defineComponent({
  14 + components: { BasicForm },
  15 +
  16 + props: {
  17 + detailData: {
  18 + type: Object,
  19 + },
  20 + onGoCheckDetail: {
  21 + type: Function,
  22 + },
  23 + id: {
  24 + type: String,
  25 + },
  26 + },
  27 + emits: ['success'],
  28 + setup(props, { emit }) {
  29 + console.log('%c [ props ]-29', 'font-size:13px; background:pink; color:#bf2c9f;', props);
  30 + let fields = reactive({ profitAnalysisInfo: {} });
  31 +
  32 + const schemas = computed(() => {
  33 + return FIELDS_PROFIT_INFO.map((item) => {
  34 + console.log(
  35 + '%c [ ]-31',
  36 + 'font-size:13px; background:pink; color:#bf2c9f;',
  37 + get(fields, `${item.field}`),
  38 + getDisable(get(fields, `${item.field}`), props.id),
  39 + );
  40 + return {
  41 + ...item,
  42 + componentProps: {
  43 + ...item.componentProps,
  44 + disabled: getDisable(get(fields, `${item.field}`), props.id),
  45 + },
  46 + colProps: {
  47 + span: 24,
  48 + },
  49 + };
  50 + });
  51 + });
  52 +
  53 + const [registerForm, { setFieldsValue, getFieldsValue, reload }] = useForm({
  54 + labelWidth: 120,
  55 + schemas,
  56 + showActionButtonGroup: false,
  57 + actionColOptions: {
  58 + span: 24,
  59 + },
  60 + });
  61 + return { fields, schemas, registerForm, getFieldsValue, setFieldsValue };
  62 + },
  63 + });
  64 +</script>
... ...
src/views/project/order/component/ReportFormPanel.vue 0 → 100644
  1 +<template>
  2 + <BasicForm @register="registerForm" />
  3 +</template>
  4 +<script lang="ts">
  5 + import { computed, defineComponent, reactive, ref, toRaw } from 'vue';
  6 + import { BasicForm, FormActionType, useForm } from '/@/components/Form/index';
  7 + import { dateUtil } from '/@/utils/dateUtil';
  8 + import { FIELDS_REPORT_INFO } from '../tableData';
  9 + import { getDisable } from '/@/utils/project';
  10 + import { useOrderStoreWithOut } from '/@/store/modules/order';
  11 + import { useDrawerInner } from '/@/components/Drawer';
  12 +
  13 + import { useOrderInfo } from '/@/hooks/component/order';
  14 +
  15 + export default defineComponent({
  16 + components: { BasicForm },
  17 +
  18 + props: {
  19 + detailData: {
  20 + type: Object,
  21 + },
  22 + onGoCheckDetail: {
  23 + type: Function,
  24 + },
  25 + },
  26 + emits: ['success'],
  27 + setup(_, { emit }) {
  28 + let fields = reactive({ baseFields: {}, profitAnalysisInfo: {} });
  29 + const orderStore = useOrderStoreWithOut();
  30 +
  31 + const { ideaSource, manualPreform } = useOrderInfo(orderStore);
  32 +
  33 + const schemas = computed(() => {
  34 + const options = {
  35 + ideaSource,
  36 + manualPreform,
  37 + };
  38 + return FIELDS_REPORT_INFO.map((item) => ({
  39 + ...item,
  40 + componentProps: {
  41 + ...(item.component === 'Select' && { options: options[item.optionField] }),
  42 + disabled: getDisable(`fields.${item.field}`),
  43 + },
  44 + colProps: {
  45 + span: 24,
  46 + },
  47 + }));
  48 + });
  49 +
  50 + const [registerForm, { setFieldsValue, getFieldsValue, reload }] = useForm({
  51 + labelWidth: 120,
  52 + schemas,
  53 + showActionButtonGroup: false,
  54 + actionColOptions: {
  55 + span: 24,
  56 + },
  57 + });
  58 +
  59 + const [register, { closeDrawer }] = useDrawerInner((data) => {
  60 + // 方式1
  61 + data.orderHodTime = data.orderHodTime ? dateUtil(data.orderHodTime) : null;
  62 + data.productionDepartmentConsignTime = data.productionDepartmentConsignTime
  63 + ? dateUtil(data.productionDepartmentConsignTime)
  64 + : null;
  65 +
  66 + fields.baseFields = {
  67 + ...fields.baseFields,
  68 + ...data.lockFields.baseFields,
  69 + };
  70 +
  71 + if (id.value) {
  72 + setFieldsValue({
  73 + ...toRaw(data),
  74 + baseInfo: { ...toRaw(data) },
  75 + });
  76 + } else {
  77 + setFieldsValue({});
  78 + }
  79 + });
  80 +
  81 + return { register, schemas, registerForm, getFieldsValue };
  82 + },
  83 + });
  84 +</script>
... ...
src/views/project/order/component/TrackFormPanel.vue 0 → 100644
  1 +<!-- 跟单信息 -->
  2 +<template>
  3 + <BasicForm @register="registerForm" />
  4 +</template>
  5 +<script lang="ts">
  6 + import { computed, defineComponent, reactive, ref, toRaw } from 'vue';
  7 + import { BasicForm, FormActionType, useForm } from '/@/components/Form/index';
  8 + import { useDrawerInner } from '/@/components/Drawer';
  9 + import { dateUtil } from '/@/utils/dateUtil';
  10 + import { FIELDS_TRACK_STAGE_INFO } from '../tableData';
  11 + import { getDisable } from '/@/utils/project';
  12 +
  13 + export default defineComponent({
  14 + components: { BasicForm },
  15 +
  16 + props: {
  17 + detailData: {
  18 + type: Object,
  19 + },
  20 + onGoCheckDetail: {
  21 + type: Function,
  22 + },
  23 + },
  24 + emits: ['success'],
  25 + setup(_, { emit }) {
  26 + let fields = reactive({ baseFields: {}, profitAnalysisInfo: {} });
  27 +
  28 + const schemas = computed(() => {
  29 + return FIELDS_TRACK_STAGE_INFO.map((item) => ({
  30 + ...item,
  31 + componentProps: {
  32 + ...item.componentProps,
  33 + disabled: getDisable(`fields.${item.field}`),
  34 + },
  35 + colProps: {
  36 + span: 24,
  37 + },
  38 + }));
  39 + });
  40 +
  41 + const [registerForm, { setFieldsValue, getFieldsValue, reload }] = useForm({
  42 + labelWidth: 120,
  43 + schemas,
  44 + showActionButtonGroup: false,
  45 + actionColOptions: {
  46 + span: 24,
  47 + },
  48 + });
  49 +
  50 + const [register, { closeDrawer }] = useDrawerInner((data) => {
  51 + // 方式1
  52 + data.orderHodTime = data.orderHodTime ? dateUtil(data.orderHodTime) : null;
  53 + data.productionDepartmentConsignTime = data.productionDepartmentConsignTime
  54 + ? dateUtil(data.productionDepartmentConsignTime)
  55 + : null;
  56 +
  57 + fields.baseFields = {
  58 + ...fields.baseFields,
  59 + ...data.lockFields.baseFields,
  60 + };
  61 +
  62 + if (id.value) {
  63 + setFieldsValue({
  64 + ...toRaw(data),
  65 + baseInfo: { ...toRaw(data) },
  66 + });
  67 + } else {
  68 + setFieldsValue({});
  69 + }
  70 + });
  71 +
  72 + return { register, schemas, registerForm, getFieldsValue };
  73 + },
  74 + });
  75 +</script>
... ...
src/views/project/order/data.tsx 0 → 100644
  1 +export const cardList = (() => {
  2 + const result: any[] = [];
  3 + for (let i = 0; i < 6; i++) {
  4 + result.push({
  5 + id: i,
  6 + title: 'Vben Admin',
  7 + description: '基于Vue Next, TypeScript, Ant Design Vue实现的一套完整的企业级后台管理系统',
  8 + datetime: '2020-11-26 17:39',
  9 + extra: '编辑',
  10 + icon: 'logos:vue',
  11 + color: '#1890ff',
  12 + author: 'Vben',
  13 + percent: 20 * (i + 1),
  14 + });
  15 + }
  16 + return result;
  17 +})();
... ...
src/views/project/order/index.vue 0 → 100644
  1 +<template>
  2 + <div>
  3 + <BasicTable @register="registerTable" bordered>
  4 + <template #headerCell="{ column }">
  5 + <!-- <template v-if="column.key === 'address1'">
  6 + <span class="flex items-center justify-center"> 自定义字段列11 </span>
  7 + </template> -->
  8 + <template v-if="SELECT_FIELD_COLUMNS.includes(column.key)">
  9 + <span class="flex items-center justify-center">
  10 + {{ column.customTitle }}
  11 + <FormOutlined class="ml-2 cursor-pointer" @click="handleFieldVisible(column)" />
  12 + </span>
  13 + </template>
  14 + <template v-else>
  15 + <HeaderCell :column="column" />
  16 + </template>
  17 + </template>
  18 + <template #headerTop>
  19 + <a-alert type="info" show-icon>
  20 + <template #message>
  21 + <template v-if="checkedKeys.length > 0">
  22 + <span>已选中{{ checkedKeys.length }}条记录(可跨页)</span>
  23 + <a-button type="link" @click="checkedKeys = []" size="small">清空</a-button>
  24 + </template>
  25 + <template v-else>
  26 + <span>未选中任何订单</span>
  27 + </template>
  28 + </template>
  29 + </a-alert>
  30 + </template>
  31 + <template #bodyCell="{ column, record }">
  32 + <template v-if="column.key === 'action'">
  33 + <TableAction
  34 + :actions="[
  35 + {
  36 + label: '编辑',
  37 + // icon: 'ic:outline-delete-outline',
  38 + onClick: handleEdit.bind(null, record),
  39 + },
  40 + {
  41 + label: '申请权限',
  42 + // icon: 'ic:outline-delete-outline',
  43 + onClick: handleCheck.bind(null, record),
  44 + },
  45 + ]"
  46 + :dropDownActions="[
  47 + // {
  48 + // label: '启用',
  49 + // popConfirm: {
  50 + // title: '是否启用?',
  51 + // confirm: handleOpen.bind(null, record),
  52 + // },
  53 + // },
  54 + {
  55 + label: '历史记录',
  56 + onClick: handleHistory.bind(null, record),
  57 + },
  58 + ]"
  59 + />
  60 + </template>
  61 + <template v-if="column.key === 'picUrl'">
  62 + <img
  63 + :width="100"
  64 + :height="100"
  65 + :src="record.picUrl"
  66 + :key="record.picUrl"
  67 + @click="handlePreview(record.picUrl)"
  68 + />
  69 + </template>
  70 + </template>
  71 +
  72 + <template #toolbar>
  73 + <a-button type="primary" @click="handleExport">导出</a-button>
  74 + <a-button type="primary" @click="handleProfitModal" :disabled="!checkedKeys.length"
  75 + >分析利润</a-button
  76 + >
  77 + <a-button type="primary" @click="handleAdd">创建订单</a-button>
  78 + </template>
  79 + </BasicTable>
  80 + <FormDetail
  81 + @register="formDetailRegister"
  82 + :onGoCheckDetail="handleGoCheckDetail"
  83 + @success="handleFormSuccess"
  84 + />
  85 + <ProfitAnalysis @register="profitModalRegister" />
  86 + <CheckDetail @register="checkModalRegister" :onGoFormDetail="handleGoFormDetail" />
  87 + <HistoryDetail @register="historyDetailRegister" />
  88 + <FieldDetail @register="fieldDetailRegister" />
  89 + </div>
  90 +</template>
  91 +<script lang="ts">
  92 + import { defineComponent, onMounted, ref, toRaw, toRefs, unref } from 'vue';
  93 + import { BasicTable, useTable, TableAction } from '/@/components/Table';
  94 + import { FormOutlined } from '@ant-design/icons-vue';
  95 + import HeaderCell from '/@/components/Table/src/components/HeaderCell.vue';
  96 + import { Alert } from 'ant-design-vue';
  97 + import { SELECT_FIELD_COLUMNS } from './selectData';
  98 +
  99 + import { useDrawer } from '/@/components/Drawer';
  100 + import ProfitAnalysis from './ProfitAnalysis.vue';
  101 + import { useModal } from '/@/components/Modal';
  102 +
  103 + import { getFormConfig, getOrderColumns } from './tableData';
  104 + import FormDetail from './FormDetail.vue';
  105 + import CheckDetail from './CheckDetail.vue';
  106 + import HistoryDetail from './HistoryDetail.vue';
  107 + import FieldDetail from './FieldDetail.vue';
  108 + import { createImgPreview } from '/@/components/Preview/index';
  109 + import { getOrderList, orderExport } from '/@/api/project/order';
  110 + import { useOrderStoreWithOut } from '/@/store/modules/order';
  111 +
  112 + const orderStore = useOrderStoreWithOut();
  113 +
  114 + export default defineComponent({
  115 + components: {
  116 + HeaderCell,
  117 + BasicTable,
  118 + AAlert: Alert,
  119 + TableAction,
  120 + FormDetail,
  121 + ProfitAnalysis,
  122 + FormOutlined,
  123 + CheckDetail,
  124 + HistoryDetail,
  125 + FieldDetail,
  126 + },
  127 + setup() {
  128 + const checkedKeys = ref<Array<string | number>>([]);
  129 + const [profitModalRegister, { openModal: openProfitModal }] = useModal();
  130 + const tooltipVisible = ref(false);
  131 + const [formDetailRegister, { openDrawer: openFormDetailDrawer }] = useDrawer();
  132 + const [historyDetailRegister, { openDrawer: openHistoryDetailDrawer }] = useDrawer();
  133 + const [fieldDetailRegister, { openDrawer: openFieldDetailDrawer }] = useDrawer();
  134 +
  135 + const [checkModalRegister, { openDrawer: openCheckDetailDrawer }] = useDrawer();
  136 + onMounted(async () => {
  137 + await orderStore.getDict();
  138 + });
  139 +
  140 + const [registerTable, { getForm, reload }] = useTable({
  141 + api: getOrderList,
  142 + title: '订单列表',
  143 + // api: () => {
  144 + // const res = demoListApi();
  145 + // total.value = res.data.total;
  146 + // return res;
  147 + // // },
  148 + // pagination: {
  149 + // total: 30,
  150 + // },
  151 + pagination: {
  152 + total: 60,
  153 + },
  154 + columns: getOrderColumns(),
  155 + useSearchForm: true,
  156 + formConfig: getFormConfig(),
  157 + showTableSetting: true,
  158 + // tableSetting: { fullScreen: true },
  159 + showIndexColumn: false,
  160 + rowKey: 'id',
  161 + rowSelection: {
  162 + type: 'checkbox',
  163 + selectedRowKeys: checkedKeys,
  164 + onSelect: onSelect,
  165 + onSelectAll: onSelectAll,
  166 + },
  167 + actionColumn: {
  168 + width: 160,
  169 + title: 'Action',
  170 + dataIndex: 'action',
  171 + // slots: { customRender: 'action' },
  172 + },
  173 + });
  174 +
  175 + function getFormValues() {
  176 + console.log(getForm().getFieldsValue());
  177 + }
  178 +
  179 + function onSelect(record, selected) {
  180 + if (selected) {
  181 + checkedKeys.value = [...checkedKeys.value, record.id];
  182 + } else {
  183 + checkedKeys.value = checkedKeys.value.filter((id) => id !== record.id);
  184 + }
  185 + }
  186 + function onSelectAll(selected, selectedRows, changeRows) {
  187 + const changeIds = changeRows.map((item) => item.id);
  188 + if (selected) {
  189 + checkedKeys.value = [...checkedKeys.value, ...changeIds];
  190 + } else {
  191 + checkedKeys.value = checkedKeys.value.filter((id) => {
  192 + return !changeIds.includes(id);
  193 + });
  194 + }
  195 + }
  196 +
  197 + function handleEdit(record, e) {
  198 + openFormDetailDrawer(true, { ...toRaw(record) });
  199 + e?.stopPropagation();
  200 + return false;
  201 + }
  202 +
  203 + function handleAdd() {
  204 + openFormDetailDrawer(true);
  205 + }
  206 +
  207 + function handleCheck(record, e) {
  208 + openCheckDetailDrawer(true, record);
  209 + e?.stopPropagation();
  210 + return false;
  211 + }
  212 +
  213 + function handleHistory(record, e) {
  214 + openHistoryDetailDrawer(true, record);
  215 + e?.stopPropagation();
  216 + return false;
  217 + }
  218 +
  219 + function handleOpen(record: Recordable) {}
  220 +
  221 + function handleProfitModal() {
  222 + openProfitModal(true, {
  223 + data: checkedKeys.value,
  224 + });
  225 + }
  226 +
  227 + function handleFieldVisible(record) {
  228 + openFieldDetailDrawer(true, record);
  229 + }
  230 +
  231 + function handleGoCheckDetail() {
  232 + openCheckDetailDrawer(true);
  233 + openFormDetailDrawer(false);
  234 + }
  235 +
  236 + function handleGoFormDetail() {
  237 + openCheckDetailDrawer(false);
  238 + openFormDetailDrawer(true);
  239 + }
  240 +
  241 + function handlePreview(url, e) {
  242 + createImgPreview({ imageList: [url], defaultWidth: 500 });
  243 + // e?.stopPropagation();
  244 + // e?.preventDefault();
  245 + return false;
  246 + }
  247 +
  248 + async function handleExport() {
  249 + await orderExport();
  250 + }
  251 +
  252 + const handleFormSuccess = () => {
  253 + reload();
  254 + };
  255 +
  256 + return {
  257 + fieldDetailRegister,
  258 + profitModalRegister,
  259 + historyDetailRegister,
  260 + formDetailRegister,
  261 + handleProfitModal,
  262 + registerTable,
  263 + getFormValues,
  264 + checkedKeys,
  265 + onSelect,
  266 + handleEdit,
  267 + handleCheck,
  268 + handleOpen,
  269 + onSelectAll,
  270 + tooltipVisible,
  271 + handleFieldVisible,
  272 + checkModalRegister,
  273 + handleGoCheckDetail,
  274 + handleGoFormDetail,
  275 + handleHistory,
  276 + handleAdd,
  277 + SELECT_FIELD_COLUMNS,
  278 + createImgPreview,
  279 + handleExport,
  280 + handlePreview,
  281 + handleFormSuccess,
  282 + };
  283 + },
  284 + });
  285 +</script>
  286 +
  287 +<style>
  288 + .ant-table-thead th,
  289 + .ant-table-tbody td {
  290 + padding: 0;
  291 + white-space: pre-wrap;
  292 + }
  293 +
  294 + .ant-table-cell img {
  295 + width: 100px;
  296 + height: 100px;
  297 + }
  298 +</style>
... ...
src/views/project/order/selectData.tsx 0 → 100644
  1 +export const SELECT_FIELD_COLUMNS = [
  2 + 'projectNo',
  3 + 'customerCode',
  4 + 'innerNo',
  5 + 'poColor',
  6 + 'cnColor',
  7 + 'productStyle',
  8 + 'outboundType',
  9 + 'packetType',
  10 + 'midCheckResult',
  11 + 'endCheckResult',
  12 +];
... ...