zhangjie 1 年之前
父節點
當前提交
e67b9161a7
共有 32 個文件被更改,包括 158 次插入4829 次删除
  1. 0 222
      src/api/base.ts
  2. 1 1
      src/api/order.ts
  3. 0 300
      src/api/types/base.ts
  4. 125 0
      src/assets/style/arco-custom.less
  5. 1 0
      src/assets/style/index.less
  6. 0 68
      src/assets/style/reset.less
  7. 1 0
      src/components/import-dialog/index.vue
  8. 0 34
      src/constants/adminNavs.ts
  9. 10 7
      src/layout/default-layout.vue
  10. 0 78
      src/router/routes/modules/base.ts
  11. 12 2
      src/store/modules/app/menuData.ts
  12. 0 291
      src/views/base/card-manage/index.vue
  13. 0 141
      src/views/base/card-rule-manage/CardTitleRuleEdit.vue
  14. 0 307
      src/views/base/card-rule-manage/ModifyCardRule.vue
  15. 0 305
      src/views/base/card-rule-manage/index.vue
  16. 0 288
      src/views/base/common-rule/FieldTransfer.vue
  17. 0 92
      src/views/base/common-rule/ModifyField.vue
  18. 0 155
      src/views/base/common-rule/RuleExam.vue
  19. 0 120
      src/views/base/common-rule/RulePackage.vue
  20. 0 147
      src/views/base/common-rule/RuleSign.vue
  21. 0 54
      src/views/base/common-rule/index.vue
  22. 0 133
      src/views/base/organization-manage/ModifyOrganization.vue
  23. 0 216
      src/views/base/organization-manage/index.vue
  24. 0 480
      src/views/base/print-template-manage/ModifyPrintTemplate.vue
  25. 0 236
      src/views/base/print-template-manage/index.vue
  26. 0 186
      src/views/base/role-manage/ModifyRole.vue
  27. 0 335
      src/views/base/role-manage/PrivilegeSet.vue
  28. 0 170
      src/views/base/role-manage/index.vue
  29. 0 175
      src/views/base/user-manage/ModifyUser.vue
  30. 0 274
      src/views/base/user-manage/index.vue
  31. 2 11
      src/views/login/login/ResetPwd.vue
  32. 6 1
      src/views/order/order-record-manage/index.vue

+ 0 - 222
src/api/base.ts

@@ -1,222 +0,0 @@
-import axios from 'axios';
-import type {
-  OrgTreeItem,
-  OrgItem,
-  EnableOrgData,
-  UserListFilter,
-  UserListPageParams,
-  UserListPageRes,
-  UserUpdateParams,
-  RoleItem,
-  RoleListPageParams,
-  RoleListPageRes,
-  RoleUpdateParams,
-  PrivilegeTreeItem,
-  RoleBoundPrivilegesRes,
-  ExamRuleDetailRes,
-  CardRuleListPageParams,
-  CardRuleListPageRes,
-  CardRuleItem,
-  SaveCardRuleParams,
-  EnumItem,
-  CardListParams,
-  CardListPageRes,
-  PrintTemplateListParams,
-  PrintTemplateListRes,
-  PrintTemplateItem,
-  AttachmentItem,
-} from './types/base';
-import { AbleParams } from './types/common';
-
-// common
-export const getEnums = (type: string): Promise<EnumItem[]> => {
-  return axios.post('/api/admin/common/get_enums', {}, { params: { type } });
-};
-export const attachmentDetail = (id: string): Promise<AttachmentItem> => {
-  return axios.post('/api/admin/common/file/get_one', {}, { params: { id } });
-};
-
-// user-manage
-export function userListPage(
-  params: UserListPageParams
-): Promise<UserListPageRes> {
-  return axios.post('/api/admin/sys/user/list', {}, { params });
-}
-export function updateUser(datas: UserUpdateParams): Promise<boolean> {
-  return axios.post('/api/admin/sys/user/save', datas);
-}
-export function ableUser(params: AbleParams): Promise<boolean> {
-  return axios.post('/api/admin/sys/user/enable', params);
-}
-export function deleteUser(id: string): Promise<boolean> {
-  return axios.post('/api/admin/sys/user/remove', {}, { params: { id } });
-}
-export function resetPwd(id: string): Promise<boolean> {
-  return axios.post(
-    '/api/admin/sys/user/reset_password',
-    {},
-    { params: { id } }
-  );
-}
-export function userRoleListPage(): Promise<RoleItem[]> {
-  return axios.post('/api/admin/sys/role/list_to_user', {});
-}
-
-export function exportUser(params: UserListFilter): Promise<Blob> {
-  return axios.post(
-    '/api/admin/sys/user/export',
-    {},
-    {
-      params,
-      responseType: 'blob',
-    }
-  );
-}
-
-// role-manage
-export function roleListPage(
-  params: RoleListPageParams
-): Promise<RoleListPageRes> {
-  return axios.post('/api/admin/sys/role/list', {}, { params });
-}
-export function ableRole(params: AbleParams): Promise<boolean> {
-  return axios.post('/api/admin/sys/role/enable', params);
-}
-export function updateRole(datas: RoleUpdateParams): Promise<boolean> {
-  return axios.post('/api/admin/sys/role/save', datas);
-}
-export function deleteRole(id: string): Promise<boolean> {
-  return axios.post('/api/admin/sys/role/remove', {}, { params: { id } });
-}
-export function userBoundRoles(userId: string): Promise<boolean> {
-  return axios.post(
-    '/api/admin/sys/role/get_user_roles',
-    {},
-    { params: { userId } }
-  );
-}
-// role-menu-manage
-export function privilegeList(): Promise<PrivilegeTreeItem[]> {
-  return axios.post('/api/admin/sys/privilege/list', {});
-}
-export function roleBoundPrivileges(
-  roleId: string
-): Promise<RoleBoundPrivilegesRes> {
-  return axios.post(
-    '/api/admin/sys/privilege/get_role_privileges',
-    {},
-    { params: { roleId } }
-  );
-}
-// role-user-manage
-export function roleGroupList(params) {
-  return axios.post('/api/admin/sys/role/group/list', {}, { params });
-}
-export function updateRoleGroup(datas) {
-  return axios.post('/api/admin/sys/role/group/save', datas);
-}
-
-// organization-manage
-export function organizationList(): Promise<OrgTreeItem[]> {
-  return axios.post('/api/admin/sys/org/list', {});
-}
-export function updateOrganization(datas: OrgItem): Promise<boolean> {
-  return axios.post('/api/admin/sys/org/save', datas);
-}
-export function ableOrganization(datas: EnableOrgData): Promise<boolean> {
-  return axios.post('/api/admin/sys/org/enable', datas);
-}
-export function deleteOrganization(id: string): Promise<boolean> {
-  return axios.post('/api/admin/sys/org/remove', { id });
-}
-
-// common-rule
-export function examRuleDetail(): Promise<ExamRuleDetailRes> {
-  return axios.post('/api/admin/basic/exam_rule/list', {});
-}
-export function saveExamRule(datas: ExamRuleDetailRes): Promise<number> {
-  return axios.post('/api/admin/basic/exam_rule/save', datas);
-}
-
-// card-rule
-export function cardRuleListPage(
-  params: CardRuleListPageParams
-): Promise<CardRuleListPageRes> {
-  return axios.post('/api/admin/basic/card_rule/list', {}, { params });
-}
-export function cardRuleQuery(): Promise<CardRuleItem[]> {
-  return axios.post('/api/admin/basic/card_rule/query', {});
-}
-export function cardRuleDetail(id: string): Promise<boolean> {
-  return axios.post('/api/admin/basic/card_rule/get_one', { params: { id } });
-}
-export function saveCardRule(datas: SaveCardRuleParams): Promise<boolean> {
-  return axios.post('/api/admin/basic/card_rule/save', datas);
-}
-export function ableCardRule(params: AbleParams): Promise<boolean> {
-  return axios.post('/api/admin/basic/card_rule/enable', params);
-}
-export function deleteCardRule(id: string): Promise<boolean> {
-  return axios.post('/api/admin/basic/card_rule/delete', { id });
-}
-// card-manage
-export function cardListPage(params: CardListParams): Promise<CardListPageRes> {
-  return axios.post('/api/admin/exam/card/page', {}, { params });
-}
-export function updateCard(datas) {
-  return axios.post('/api/admin/exam/card/save_generic', datas);
-}
-export function deleteCard(id: string): Promise<boolean> {
-  return axios.post(
-    '/api/admin/exam/card/delete_generic',
-    {},
-    { params: { id } }
-  );
-}
-export function convertCardImage(id: string): Promise<boolean> {
-  return axios.post(
-    '/api/admin/exam/card/convert_image',
-    {},
-    { params: { id } }
-  );
-}
-export function downloadCardFile(id: string): Promise<Blob> {
-  return axios.post(
-    '/api/admin/exam/card/download_card',
-    {},
-    {
-      responseType: 'blob',
-      params: { id },
-    }
-  );
-}
-
-// print-template-manage
-export const templateListPage = (
-  params: PrintTemplateListParams
-): Promise<PrintTemplateListRes> => {
-  return axios.post('/api/admin/basic/template/list', {}, { params });
-};
-export const templateDetail = (id: string): Promise<PrintTemplateItem> => {
-  return axios.post(
-    '/api/admin/basic/template/get_one',
-    {},
-    { params: { id } }
-  );
-};
-export const updateTemplate = (datas) => {
-  return axios.post('/api/admin/basic/template/save', datas);
-};
-export const ableTemplate = (params: AbleParams): Promise<boolean> => {
-  return axios.post('/api/admin/basic/template/enable', {}, { params });
-};
-export const deleteTemplate = (id: string): Promise<boolean> => {
-  return axios.post('/api/admin/basic/template/remove', {}, { params: { id } });
-};
-export const templateContentView = (id: string): Promise<string> => {
-  return axios.post(
-    '/api/admin/basic/template/read_content',
-    {},
-    { params: { id } }
-  );
-};

+ 1 - 1
src/api/order.ts

@@ -55,7 +55,7 @@ export function orderRecordCancel(id: number): Promise<boolean> {
 }
 // 预约名单详情-一键自动分配
 export function orderRecordAutoAssign(params: {
-  taskId?: number;
+  taskId: number;
 }): Promise<boolean> {
   return axios.post('/api/apply/std/auto/assign', {}, { params });
 }

+ 0 - 300
src/api/types/base.ts

@@ -1,300 +0,0 @@
-import {
-  CARD_CREATE_METHOD_TYPE,
-  CARD_TYPE,
-  DATA_PRIVILEGE_TYPE,
-  EXAM_NUMBER_STYLE,
-  TEMPLATE_CLASSIFY,
-} from '@/constants/enumerate';
-import { PageResult, PageParams } from './common';
-import { UserMenuItem } from './user';
-
-export interface EnumItem {
-  name: string;
-  ordinal: number;
-  code: string;
-  desc: string;
-  enable: boolean;
-  disabled: boolean;
-}
-export interface AttachmentItem {
-  id: string;
-  createId: string;
-  createTime: number;
-  updateId: string | null;
-  updateTime: number;
-  name: string;
-  path: string;
-  type: string;
-  size: number;
-  md5: string;
-}
-
-export interface OrgItem {
-  id: string;
-  schoolId: string;
-  code: string;
-  name: string;
-  parentId: string | null;
-  enable: boolean;
-  type: string;
-}
-
-export type OrgTreeItem = { children: OrgTreeItem[] } & OrgItem;
-
-export type EnableOrgData = Pick<OrgItem, 'id' | 'enable'>;
-
-export interface RoleItem {
-  id: string;
-  createId: string;
-  createTime: number;
-  updateId: string;
-  updateTime: number;
-  schoolId: string;
-  orgId: string;
-  name: string;
-  enable: boolean;
-  type: string;
-  privilegeIds: string;
-  defaultRole: boolean;
-  source: string;
-  interpret: boolean;
-}
-
-export interface UserItem {
-  id: string;
-  schoolId: string;
-  loginName: string;
-  realName: string;
-  mobileNumber: string;
-  enable: boolean;
-  remark: string;
-  orgId: string;
-  orgName: string;
-  code: string;
-  allowManualCard: boolean;
-  roles: RoleItem[];
-}
-
-export type UserListPageRes = PageResult<UserItem>;
-
-export interface UserListFilter {
-  orgId: string;
-  userInfo: string;
-  roleId: string;
-  enable: boolean;
-}
-export type UserListPageParams = PageParams<UserListFilter>;
-
-export interface UserUpdateParams {
-  id?: string;
-  loginName: string;
-  realName: string;
-  //   code: "",
-  mobileNumber: string;
-  allowManualCard: number;
-  roleIds: string[];
-  courseIds: string[];
-  orgId: string[];
-}
-
-export type RoleListPageParams = PageParams<{
-  name: string;
-}>;
-export type RoleListPageRes = PageResult<RoleItem>;
-
-export type DataPermissionTypeEnum = keyof typeof DATA_PRIVILEGE_TYPE;
-
-export interface RoleUpdateParams {
-  id?: string;
-  name: string;
-  interpret: string;
-  dataPermissionType: DataPermissionTypeEnum;
-  privilegeIds: string[];
-  defaultRole: boolean;
-}
-
-export type PrivilegeTreeItem = {
-  children: PrivilegeTreeItem[];
-} & UserMenuItem;
-
-export interface RoleBoundPrivilegesRes {
-  id: string;
-  name: string;
-  privilegeIds: string[];
-  dataPermissionInfo: Array<{
-    privilegeId: string;
-    dataPermissionType: DataPermissionTypeEnum;
-  }>;
-  defaultPrivilegeIds: string[];
-  defaultRole: boolean;
-  interpret: string;
-}
-
-export interface ExamRuleItem {
-  name: string;
-  code: string;
-  enable: boolean;
-  disabled?: boolean;
-  rate?: number;
-  ordinal?: number;
-}
-
-export interface SignScope {
-  basic: ExamRuleItem[];
-  table: ExamRuleItem[];
-}
-export interface PackageScope {
-  title: ExamRuleItem[];
-  basic: ExamRuleItem[];
-}
-export interface ExamRuleDetailRes {
-  id: string;
-  createId: string;
-  createTime: number;
-  updateId: string;
-  updateTime: number;
-  schoolId: string;
-  orgId: string;
-  requiredFields: string;
-  extendFields: string;
-  signScope: string;
-  packageScope: string;
-}
-
-export interface CardRuleListFilter {
-  enable: boolean;
-  name: string;
-  createStartTime: number;
-  createEndTime: number;
-}
-export type CardRuleListPageParams = PageParams<CardRuleListFilter>;
-
-export type ExamNumberStyleType = keyof typeof EXAM_NUMBER_STYLE;
-
-export interface CardRuleItem {
-  id: string;
-  createId: string;
-  createTime: number;
-  updateId: string;
-  updateTime: number;
-  schoolId: string;
-  orgId: string;
-  name: string;
-  examNumberStyle: ExamNumberStyleType;
-  examNumberDigit: number;
-  paperType: string;
-  examAbsent: boolean;
-  writeSign: boolean;
-  discipline: boolean;
-  undertakingEnable: boolean;
-  undertakingBody: string;
-  requiredFields: string;
-  extendFields: string;
-  titleRule: string;
-  attention: string;
-  objectiveAttention: string;
-  subjectiveAttention: string;
-  enable: boolean;
-  remark: string;
-  fillNumber: null;
-  orgIds: null;
-}
-export type CardRuleListPageRes = PageResult<CardRuleItem>;
-
-export interface SaveCardRuleParams {
-  id: string | null;
-  name: string;
-  remark: string;
-  examNumberStyle: string;
-  examNumberDigit: number;
-  paperType: string;
-  examAbsent: boolean;
-  discipline: boolean;
-  writeSign: boolean;
-  requiredFields: string;
-  extendFields: string;
-  titleRule: string;
-  attention: string;
-  objectiveAttention: string;
-  subjectiveAttention: string;
-}
-
-export interface CardRuleType extends SaveCardRuleParams {
-  requiredFields: ExamRuleItem[];
-  extendFields: ExamRuleItem[];
-}
-
-export interface CardListFilter {
-  title: string;
-  cardType: string;
-  createMethod: string;
-  createStartTime: number;
-  createEndTime: number;
-}
-export type CardListParams = PageParams<CardListFilter>;
-
-export type CardType = keyof typeof CARD_TYPE;
-export type CardCreateMethodType = keyof typeof CARD_CREATE_METHOD_TYPE;
-
-export interface CardItem {
-  id: string;
-  createId: string;
-  createTime: number;
-  updateId: string;
-  updateTime: number;
-  schoolId: string;
-  orgId: string;
-  courseCode: string;
-  courseName: string;
-  title: string;
-  makeMethod: string;
-  status: 'SUBMIT' | 'STAGE';
-  type: CardType;
-  createMethod: CardCreateMethodType;
-  attachmentId: string;
-  enable: boolean;
-  used: boolean;
-  remark: string;
-  cardRuleId: string;
-  content: string;
-  stageContent: string | null;
-  htmlContent: string | null;
-  backupAttachment: string | null;
-  jpgAttachment: string;
-  imageUrls: string[];
-}
-export type CardListPageRes = PageResult<CardItem>;
-
-export interface PrintTemplateListFilter {
-  enable: boolean | null;
-  name: string;
-  startTime: number;
-  endTime: number;
-}
-export type PrintTemplateListParams = PageParams<PrintTemplateListFilter>;
-
-export type TemplateClassifyType = keyof typeof TEMPLATE_CLASSIFY;
-export interface PrintTemplateItem {
-  id: string;
-  createId: string;
-  createTime: number;
-  updateId: string;
-  updateTime: number | null;
-  schoolId: string;
-  orgId: string | null;
-  name: string;
-  classify: TemplateClassifyType;
-  displayRange: string | null;
-  previewPath: string | null;
-  attachmentId: string | null;
-  enable: boolean;
-  diallel: boolean;
-  addBlankPage: boolean;
-  lineHeightTimes: number;
-  fontSize: string;
-  textDesc: string | null;
-  remark: string | null;
-  orgIds: string | null;
-  url: string | null;
-}
-export type PrintTemplateListRes = PageResult<PrintTemplateItem>;

+ 125 - 0
src/assets/style/arco-custom.less

@@ -0,0 +1,125 @@
+// arco-btn
+.arco-btn + .arco-btn {
+  margin-left: 10px;
+}
+.arco-btn-text {
+  &.arco-btn-status-normal {
+    color: var(--color-text-dark) !important;
+    font-weight: 400;
+  }
+  &:not(.arco-btn-only-icon) .arco-btn-icon {
+    margin-right: 4px;
+  }
+}
+// .arco-pagination
+.arco-table-pagination {
+  display: block;
+}
+.arco-pagination {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+
+  .arco-pagination-item {
+    border: 1px solid var(--color-border);
+    line-height: 30px;
+  }
+  .arco-pagination-item-active {
+    border-color: var(--color-primary);
+    background-color: var(--color-primary);
+    color: #fff;
+  }
+  .arco-select-view-single {
+    border-color: var(--color-border);
+  }
+  .arco-pagination-total {
+    flex-grow: 2;
+  }
+}
+
+// arco-table
+.action-column {
+  .arco-btn {
+    height: 20px;
+    padding: 0;
+    border: none !important;
+    outline: none !important;
+    line-height: 20px;
+    margin: 0;
+
+    &:not(:first-child) {
+      margin-left: 10px;
+    }
+    &:not(.arco-btn-disabled):hover {
+      transform: scale(1.1);
+    }
+  }
+}
+
+// arco-input
+.arco-input-wrapper,
+.arco-select-view-single {
+  border-color: #d9d9d9;
+  background-color: transparent;
+}
+.arco-input-wrapper:not(.arco-input-focus),
+.arco-select-view-single:not(.arco-select-view-focus) {
+  &:hover {
+    border-color: #bebebe;
+    background-color: transparent;
+  }
+}
+
+// arco-modal
+.arco-modal {
+  border-radius: 8px;
+
+  .arco-modal-close-btn {
+    font-size: 20px;
+  }
+  .arco-icon-hover::before {
+    width: 24px;
+    height: 24px;
+    border-radius: 4px;
+  }
+  .arco-modal-header {
+    padding: 20px;
+    border-bottom: 1px solid var(--color-border);
+    margin: 0;
+    height: auto;
+    text-align: left;
+  }
+  .arco-modal-title {
+    color: var(--color-text-dark);
+  }
+  .arco-modal-close {
+    width: 24px;
+    height: 24px;
+  }
+  .arco-modal-body {
+    padding: 20px;
+  }
+  .arco-modal-footer {
+    padding: 0 20px 20px;
+    margin: 0;
+    border: none;
+
+    .arco-btn:not(:nth-child(1)) {
+      margin-left: 8px;
+    }
+  }
+}
+.arco-modal-simple {
+  border-radius: 8px;
+  padding: 0;
+  .arco-modal-header {
+    border: none;
+    padding-bottom: 8px;
+  }
+  .arco-modal-body {
+    padding: 0 20px 20px 48px;
+  }
+  .arco-modal-footer {
+    text-align: right;
+  }
+}

+ 1 - 0
src/assets/style/index.less

@@ -1,5 +1,6 @@
 @import url('./var.less');
 @import url('./reset.less');
+@import url('./arco-custom.less');
 @import url('./base.less');
 @import url('./home.less');
 @import url('./pages.less');

+ 0 - 68
src/assets/style/reset.less

@@ -135,71 +135,3 @@ body {
     fill: inherit;
   }
 }
-
-// arco ------->
-.arco-btn + .arco-btn {
-  margin-left: 10px;
-}
-.arco-btn-text {
-  &.arco-btn-status-normal {
-    color: var(--color-text-dark) !important;
-    font-weight: 400;
-  }
-  &:not(.arco-btn-only-icon) .arco-btn-icon {
-    margin-right: 4px;
-  }
-}
-// .arco-pagination
-.arco-table-pagination {
-  display: block;
-}
-.arco-pagination {
-  display: flex;
-  justify-content: space-between;
-  align-items: center;
-
-  .arco-pagination-item {
-    border: 1px solid var(--color-border);
-    line-height: 30px;
-  }
-  .arco-pagination-item-active {
-    border-color: var(--color-primary);
-    background-color: var(--color-primary);
-    color: #fff;
-  }
-  .arco-select-view-single {
-    border-color: var(--color-border);
-  }
-  .arco-pagination-total {
-    flex-grow: 2;
-  }
-}
-.action-column {
-  .arco-btn {
-    height: 20px;
-    padding: 0;
-    border: none !important;
-    outline: none !important;
-    line-height: 20px;
-    margin: 0;
-
-    &:not(:first-child) {
-      margin-left: 10px;
-    }
-    &:not(.arco-btn-disabled):hover {
-      transform: scale(1.1);
-    }
-  }
-}
-.arco-input-wrapper,
-.arco-select-view-single {
-  border-color: #d9d9d9;
-  background-color: transparent;
-}
-.arco-input-wrapper:not(.arco-input-focus),
-.arco-select-view-single:not(.arco-select-view-focus) {
-  &:hover {
-    border-color: #bebebe;
-    background-color: transparent;
-  }
-}

+ 1 - 0
src/components/import-dialog/index.vue

@@ -3,6 +3,7 @@
     v-model:visible="visible"
     :width="500"
     :title="title"
+    title-align="start"
     @before-open="modalBeforeOpen"
   >
     <slot></slot>

+ 0 - 34
src/constants/adminNavs.ts

@@ -1,34 +0,0 @@
-const navs = [
-  {
-    id: '1',
-    parentId: '-1',
-    name: '超管中心',
-    url: 'admin',
-  },
-  {
-    id: '2',
-    parentId: '1',
-    name: '学校管理',
-    url: 'SchoolManage',
-  },
-  {
-    id: '4',
-    parentId: '1',
-    name: '角色管理',
-    url: 'SystemRoleManage',
-  },
-  {
-    id: '6',
-    parentId: '1',
-    name: '授权配置',
-    url: 'AuthSet',
-  },
-  {
-    id: '7',
-    parentId: '1',
-    name: '扫描日志',
-    url: 'ScanLogManage',
-  },
-];
-
-export default navs;

+ 10 - 7
src/layout/default-layout.vue

@@ -5,12 +5,16 @@
         <h1 class="home-title">预约报名系统</h1>
       </div>
       <div class="head-action">
-        <a-tooltip content="修改密码" position="br">
+        <div class="home-action-item">
+          <svg-icon name="icon-user" fill="#BFBFBF" />
+          <span :title="userStore.name">{{ userStore.name }}</span>
+        </div>
+        <!-- <a-tooltip content="修改密码" position="br">
           <div class="home-action-item cursor" @click="toResetPwd">
             <svg-icon name="icon-user" fill="#BFBFBF" />
             <span :title="userStore.name">{{ userStore.name }}</span>
           </div>
-        </a-tooltip>
+        </a-tooltip> -->
         <a-tooltip content="退出登录" position="br">
           <div class="home-action-item cursor" @click="toLogout">
             <svg-icon name="icon-logout" />
@@ -88,7 +92,6 @@
 <script lang="ts" setup>
   import { onMounted, ref, watch } from 'vue';
   import { useRoute, useRouter } from 'vue-router';
-  import { IconHome, IconUser, IconExport } from '@arco-design/web-vue/es/icon';
   import { useAppStore, useUserStore } from '@/store';
   import { modalConfirm } from '@/utils/arco';
 
@@ -110,7 +113,7 @@
     mobileNumber: 1,
     userId: userStore.id,
   });
-  const ResetPwdRef = ref(null);
+  // const ResetPwdRef = ref(null);
 
   function initData() {
     curRouteName.value = route.name;
@@ -121,9 +124,9 @@
     router.push({ name: val });
   }
 
-  function toResetPwd() {
-    ResetPwdRef.value?.open();
-  }
+  // function toResetPwd() {
+  //   ResetPwdRef.value?.open();
+  // }
 
   function resetPwdModified() {
     userStore.logout();

+ 0 - 78
src/router/routes/modules/base.ts

@@ -1,78 +0,0 @@
-import { DEFAULT_LAYOUT } from '../base';
-import { AppRouteRecordRaw } from '../types';
-
-const BASE: AppRouteRecordRaw = {
-  path: '/base',
-  name: 'base',
-  component: DEFAULT_LAYOUT,
-  meta: {
-    requiresAuth: true,
-  },
-  children: [
-    {
-      path: 'organization-manage',
-      name: 'OrganizationManage',
-      component: () => import('@/views/base/organization-manage/index.vue'),
-      meta: {
-        title: '机构管理',
-        requiresAuth: true,
-      },
-    },
-    {
-      path: 'user-manage',
-      name: 'UserManage',
-      component: () => import('@/views/base/user-manage/index.vue'),
-      meta: {
-        title: '用户管理',
-        requiresAuth: true,
-      },
-    },
-    {
-      path: 'role-manage',
-      name: 'RoleManage',
-      component: () => import('@/views/base/role-manage/index.vue'),
-      meta: {
-        title: '角色管理',
-        requiresAuth: true,
-      },
-    },
-    {
-      path: 'common-rule',
-      name: 'CommonRule',
-      component: () => import('@/views/base/common-rule/index.vue'),
-      meta: {
-        title: '通用规则',
-        requiresAuth: true,
-      },
-    },
-    {
-      path: 'card-rule-manage',
-      name: 'CardRuleManage',
-      component: () => import('@/views/base/card-rule-manage/index.vue'),
-      meta: {
-        title: '题卡规则管理',
-        requiresAuth: true,
-      },
-    },
-    {
-      path: 'card-manage',
-      name: 'CardManage',
-      component: () => import('@/views/base/card-manage/index.vue'),
-      meta: {
-        title: '题卡管理',
-        requiresAuth: true,
-      },
-    },
-    {
-      path: 'print-template-manage',
-      name: 'PrintTemplateManage',
-      component: () => import('@/views/base/print-template-manage/index.vue'),
-      meta: {
-        title: '模板管理',
-        requiresAuth: true,
-      },
-    },
-  ],
-};
-
-export default BASE;

+ 12 - 2
src/store/modules/app/menuData.ts

@@ -30,12 +30,22 @@ export const menus = [
   },
   {
     id: '4',
-    name: '预约名单详情',
-    url: 'OrderRecordManage',
+    name: '考生管理',
+    url: 'ExamStudentManage',
     type: 'MENU',
     parentId: '1',
     sequence: 3,
     enable: true,
+    roles: [],
+  },
+  {
+    id: '5',
+    name: '预约明细',
+    url: 'OrderRecordManage',
+    type: 'MENU',
+    parentId: '1',
+    sequence: 4,
+    enable: true,
     roles: ['ADMIN'],
   },
 ];

+ 0 - 291
src/views/base/card-manage/index.vue

@@ -1,291 +0,0 @@
-<template>
-  <div class="part-box is-filter">
-    <a-form
-      layout="inline"
-      :model="searchModel"
-      :label-col-props="{ span: 0, offset: 0 }"
-      :wrapper-col-props="{ span: 24, offset: 0 }"
-    >
-      <template v-if="permissions.condition_condition">
-        <a-form-item label="题卡名称">
-          <a-input
-            v-model.trim="searchModel.title"
-            placeholder="题卡名称"
-            allow-clear
-          ></a-input>
-        </a-form-item>
-        <a-form-item label="题卡类型">
-          <a-select
-            v-model="searchModel.cardType"
-            placeholder="题卡类型"
-            :options="cardTypeOption"
-            filter-option
-            allow-clear
-          >
-          </a-select>
-        </a-form-item>
-        <a-form-item label="创建方式">
-          <a-select
-            v-model="searchModel.createMethod"
-            placeholder="创建方式"
-            :options="createMethodOption"
-            filter-option
-            allow-clear
-          >
-          </a-select>
-        </a-form-item>
-        <a-form-item label="创建时间">
-          <select-range-datetime
-            v-model="searchModel"
-            :keys="{
-              startTime: 'createStartTime',
-              endTime: 'createEndTime',
-            }"
-          >
-          </select-range-datetime>
-        </a-form-item>
-      </template>
-      <a-form-item>
-        <a-button
-          v-if="permissions.button_select"
-          type="primary"
-          @click="toPage(1)"
-          >查询</a-button
-        >
-      </a-form-item>
-    </a-form>
-    <div class="box-justify">
-      <div> </div>
-      <div>
-        <a-button v-if="permissions.button_add" type="primary" @click="toAdd"
-          >新增</a-button
-        >
-      </div>
-    </div>
-  </div>
-  <div class="part-box">
-    <a-table :columns="columns" :data="dataList" :pagination="pagination">
-      <template #index="{ rowIndex }">
-        {{ getRowIndex(rowIndex) }}
-      </template>
-      <template #courseCode="{ record }">
-        {{ courseNameCodeFilter(record) }}
-      </template>
-      <template #cardType="{ record }">
-        {{ getCardTypeLabel(record.roles) }}
-      </template>
-      <template #createMethod="{ record }">
-        {{ getCreateMethodLabel(record.enable) }}
-      </template>
-      <template #status="{ record }">
-        {{ record.status === 'SUBMIT' ? '提交' : '暂存' }}
-      </template>
-      <template #createTime="{ record }">
-        {{ timestampFilter(record.createTime) }}
-      </template>
-      <template #action="{ record }">
-        <a-button
-          v-if="permissions.link_preview"
-          type="text"
-          class="btn-primary"
-          @click="toPreview(record)"
-          >查看</a-button
-        >
-        <a-button
-          v-if="permissions.link_convertimage && !record.imageUrls"
-          type="text"
-          class="btn-primary"
-          @click="toConvertImage(record)"
-          >生成图片</a-button
-        >
-        <a-button
-          v-if="permissions.link_convertimage && record.imageUrls"
-          type="text"
-          class="btn-primary"
-          @click="toPreviewImage(record)"
-          >预览图片</a-button
-        >
-        <a-button
-          v-if="
-            permissions.link_delete && record.type !== 'CUSTOM' && !record.used
-          "
-          class="btn-danger"
-          type="text"
-          @click="toDelete(record)"
-          >删除</a-button
-        >
-        <a-button
-          v-if="
-            permissions.link_edit &&
-            record.createMethod !== 'UPLOAD' &&
-            !record.used
-          "
-          type="text"
-          class="btn-primary"
-          @click="toEditCard(record)"
-          >编辑题卡</a-button
-        >
-        <a-button
-          v-if="
-            permissions.link_edit && record.type !== 'CUSTOM' && !record.used
-          "
-          type="text"
-          class="btn-primary"
-          @click="toEditInfo(record)"
-          >编辑信息</a-button
-        >
-        <a-button
-          v-if="permissions.link_download"
-          type="text"
-          class="btn-primary"
-          disabled
-          @click="toDownload(record)"
-          >下载</a-button
-        >
-      </template>
-    </a-table>
-  </div>
-</template>
-
-<script setup lang="ts">
-  import { reactive, ref } from 'vue';
-  import { Message, TableColumnData } from '@arco-design/web-vue';
-  import {
-    cardListPage,
-    convertCardImage,
-    deleteCard,
-    downloadCardFile,
-  } from '@/api/base';
-  import { CardItem } from '@/api/types/base';
-  import useTable from '@/hooks/table';
-  import useDictOption from '@/hooks/dict-option';
-  import useLoading from '@/hooks/loading';
-  import usePermission from '@/hooks/permission';
-
-  import { modalConfirm } from '@/utils/arco';
-  import { downloadByApi } from '@/utils/download';
-  import { timestampFilter, courseNameCodeFilter } from '@/utils/filter';
-
-  defineOptions({
-    name: 'CardManage',
-  });
-
-  const { permissions } = usePermission();
-  const { optionList: createMethodOption, getLabel: getCreateMethodLabel } =
-    useDictOption('CARD_CREATE_METHOD_TYPE');
-  const { optionList: cardTypeOption, getLabel: getCardTypeLabel } =
-    useDictOption('CARD_TYPE');
-
-  const searchModel = reactive({
-    title: '',
-    cardType: '',
-    createMethod: '',
-    createStartTime: '',
-    createEndTime: '',
-  });
-
-  const columns: TableColumnData[] = [
-    {
-      title: '序号',
-      slotName: 'index',
-      width: 80,
-    },
-    {
-      title: '题卡名称',
-      dataIndex: 'title',
-    },
-    {
-      title: '课程(代码)',
-      dataIndex: 'courseCode',
-      slotName: 'courseCode',
-    },
-    {
-      title: '类型',
-      dataIndex: 'type',
-      slotName: 'cardType',
-    },
-    {
-      title: '创建方式',
-      dataIndex: 'createMethod',
-      slotName: 'createMethod',
-    },
-    {
-      title: '状态',
-      dataIndex: 'status',
-      slotName: 'status',
-    },
-    {
-      title: '备注',
-      dataIndex: 'remark',
-    },
-    {
-      title: '创建时间',
-      dataIndex: 'createTime',
-      slotName: 'createTime',
-    },
-    {
-      title: '操作',
-      slotName: 'action',
-      width: 220,
-      fixed: 'right',
-      cellClass: 'action-column',
-    },
-  ];
-  const { dataList, pagination, toPage, deletePageLastItem, getRowIndex } =
-    useTable<CardItem[]>(cardListPage, searchModel, permissions.button_select);
-
-  // table action
-  const modifyUserRef = ref(null);
-  const curRow = ref({});
-  function toAdd() {
-    curRow.value = {};
-    modifyUserRef.value?.open();
-  }
-  function toEditCard(row: CardItem) {
-    curRow.value = row;
-    modifyUserRef.value?.open();
-  }
-  function toEditInfo(row: CardItem) {
-    curRow.value = row;
-    modifyUserRef.value?.open();
-  }
-
-  function toPreview(row: CardItem) {
-    console.log(row);
-  }
-  async function toConvertImage(row: CardItem) {
-    await convertCardImage(row.id);
-    Message.success('操作成功!');
-  }
-
-  async function toDelete(row: CardItem) {
-    const confirmRes = await modalConfirm(
-      '提示',
-      `确定要删除题卡【${row.title}】吗?`
-    ).catch(() => false);
-    if (confirmRes !== 'confirm') return;
-
-    await deleteCard(row.id);
-    Message.success('操作成功!');
-    deletePageLastItem();
-  }
-
-  const { loading, setLoading } = useLoading();
-  async function toDownload(row: CardItem) {
-    if (loading.value) return;
-
-    setLoading(true);
-    const res = await downloadByApi(() => downloadCardFile(row.id)).catch(
-      (e) => {
-        Message.error(e || '下载失败,请重新尝试!');
-      }
-    );
-    setLoading(false);
-    if (!res) return;
-    Message.success('下载成功!');
-  }
-
-  function toPreviewImage(row: CardItem) {
-    console.log(row);
-  }
-</script>

+ 0 - 141
src/views/base/card-rule-manage/CardTitleRuleEdit.vue

@@ -1,141 +0,0 @@
-<template>
-  <div class="card-title-rule-edit">
-    <div class="field-list">
-      <div
-        v-for="field in fields"
-        :key="field.code"
-        :class="['field-item', { 'is-act': field.selected }]"
-        @mousedown="(event) => selectField(field, event)"
-      >
-        {{ field.name }}({{ field.code }})
-      </div>
-    </div>
-    <a-textarea
-      ref="fieldTextareaRef"
-      v-model="content"
-      :rows="2"
-      placeholder="请输入内容"
-      :disabled="disabled"
-      @input="contentChange"
-    >
-    </a-textarea>
-  </div>
-</template>
-
-<script setup lang="ts">
-  import { ref, watch } from 'vue';
-
-  defineOptions({
-    name: 'CardTitleRuleEdit',
-  });
-
-  interface FiedlSourceItem {
-    name: string;
-    code: string;
-    enable: boolean;
-    selected?: boolean;
-    disabled?: boolean;
-  }
-
-  const props = withDefaults(
-    defineProps<{
-      modelValue: string;
-      fieldSourses: FiedlSourceItem[];
-      disabled?: boolean;
-    }>(),
-    {
-      modelValue: '',
-      fieldSourses: () => [],
-      disabled: false,
-    }
-  );
-  const emit = defineEmits(['update:modelValue', 'change']);
-
-  const fields = ref<FiedlSourceItem[]>([]);
-  const fieldNameToCode = ref<Record<string, string>>({});
-  const fieldCodeToName = ref<Record<string, string>>({});
-  const content = ref('');
-  const fieldTextareaRef = ref(null);
-
-  function setFields(data: FiedlSourceItem[]) {
-    const selectedCodes = fields.value
-      .filter((item) => item.selected)
-      .map((item) => item.code);
-    fields.value = data.map((item) => {
-      item.selected = selectedCodes.includes(item.code);
-      return item;
-    });
-    fields.value.forEach((field) => {
-      fieldNameToCode.value[field.name] = field.code;
-      fieldCodeToName.value[field.code] = field.name;
-    });
-  }
-  function updateFieldStatus() {
-    const rexp = new RegExp(/\$\{.+?\}/, 'g');
-    const variates = content.value.match(rexp);
-    const selectedCodes = variates
-      ? variates.map((item) => item.replace('${', '').replace('}', ''))
-      : [];
-    fields.value = fields.value.map((field) => {
-      field.selected = selectedCodes.includes(field.code);
-      return field;
-    });
-  }
-  function rebuildTextarea() {
-    const soursesCodes = props.fieldSourses.map((item) => item.code);
-    const deletedCodes = fields.value.filter(
-      (item) => item.selected && !soursesCodes.includes(item.code)
-    );
-    // console.log(deletedCodes);
-    deletedCodes.forEach((field) => {
-      content.value = content.value.replace(`\${${field.code}}`, '');
-    });
-  }
-  function selectField(field: FiedlSourceItem, event: MouseEvent) {
-    if (props.disabled || !fieldTextareaRef.value) return;
-    event.preventDefault();
-
-    field.selected = !field.selected;
-    if (field.selected) {
-      // 选中
-      const variateStr = `\${${field.code}}`;
-      const textareaDom = fieldTextareaRef.value.$el.children[0];
-      const { selectionStart, selectionEnd } = textareaDom;
-
-      content.value =
-        content.value.slice(0, selectionStart) +
-        variateStr +
-        content.value.slice(selectionEnd);
-    } else {
-      // 取消
-      content.value = content.value.replace(`\${${field.code}}`, '');
-    }
-    contentChange(content.value);
-  }
-  function contentChange(val) {
-    emit('update:modelValue', val);
-    emit('change', val);
-  }
-
-  watch(
-    () => props.modelValue,
-    (val) => {
-      content.value = val;
-      updateFieldStatus();
-    },
-    {
-      immediate: true,
-    }
-  );
-  watch(
-    () => props.fieldSourses,
-    (val) => {
-      rebuildTextarea();
-      setFields(val);
-      updateFieldStatus();
-    },
-    {
-      immediate: true,
-    }
-  );
-</script>

+ 0 - 307
src/views/base/card-rule-manage/ModifyCardRule.vue

@@ -1,307 +0,0 @@
-<template>
-  <a-modal
-    v-model:visible="visible"
-    :width="950"
-    @before-open="modalBeforeOpen"
-  >
-    <template #title> {{ title }} </template>
-    <a-form
-      ref="formRef"
-      :model="formData"
-      :rules="rules"
-      size="medium"
-      auto-label-width
-    >
-      <a-form-item field="name" label="题卡规则名称">
-        <a-input
-          v-model.trim="formData.name"
-          placeholder="建议不超过30个字,规则名称不允许重复"
-          allow-clear
-        ></a-input>
-      </a-form-item>
-      <a-form-item field="remark" label="备注">
-        <a-textarea
-          v-model.trim="formData.remark"
-          placeholder="建议不超过50个字"
-          allow-clear
-          :max-length="50"
-          show-word-limit
-        ></a-textarea>
-      </a-form-item>
-      <a-form-item field="examNumberStyle" label="考号版式">
-        <a-select
-          v-model="formData.examNumberStyle"
-          placeholder="请选择考号版式"
-          :options="examNumberStyleOptions"
-          :style="{ width: '142px' }"
-          @change="numStyleChange"
-        >
-        </a-select>
-      </a-form-item>
-      <a-form-item
-        field="examNumberDigit"
-        label="考号位数"
-        :content-flex="false"
-      >
-        <a-input-number
-          v-if="examNumberStyleIsFill"
-          v-model="formData.examNumberDigit"
-          :style="{ width: '100px' }"
-          placeholder="请输入"
-          :min="5"
-          :max="15"
-          :step="1"
-        />
-        <div v-else :style="{ lineHeight: '32px' }">
-          {{ formData.examNumberDigit }}
-        </div>
-      </a-form-item>
-      <a-form-item :content-flex="false">
-        <a-space size="large" wrap>
-          <a-checkbox v-model="formData.examAbsent">启用“缺考填涂”</a-checkbox>
-          <a-checkbox v-model="formData.discipline">启用“违纪填涂”</a-checkbox>
-          <a-checkbox
-            v-model="formData.writeSign"
-            :disabled="examNumberStyleIsFill"
-            >启用“手写签名”</a-checkbox
-          >
-        </a-space>
-      </a-form-item>
-      <div class="part-box is-border">
-        <h4 class="part-box-tips">题卡版头变量印刷字段配置:</h4>
-        <a-form-item
-          label="必选字段"
-          :content-flex="false"
-          :style="{ lineHeight: '32px' }"
-        >
-          <a-space :size="[20, 0]" wrap>
-            <a-checkbox
-              v-for="column in formData.requiredFields"
-              :key="column.code"
-              v-model="column.enable"
-              disabled
-              >{{ column.name }}</a-checkbox
-            >
-          </a-space>
-        </a-form-item>
-        <a-form-item
-          label="扩展字段"
-          :content-flex="false"
-          :style="{ lineHeight: '32px' }"
-        >
-          <a-space :size="[20, 0]" wrap>
-            <a-checkbox
-              v-for="column in formData.extendFields"
-              :key="column.code"
-              v-model="column.enable"
-              >{{ column.name }}</a-checkbox
-            >
-          </a-space>
-        </a-form-item>
-      </div>
-      <a-form-item field="titleRule" label="题卡标题规则" :content-flex="false">
-        <CardTitleRuleEdit
-          v-if="fieldSourses.length"
-          v-model="formData.titleRule"
-          :field-sourses="fieldSourses"
-        />
-      </a-form-item>
-      <a-form-item prop="attention" label="注意事项" :content-flex="false">
-        <a-textarea v-model="formData.attention" :rows="4"></a-textarea>
-        <p class="tips-info">
-          提示:换行之后,题卡注意事项会展示为多条内容,内容序号会被自动添加。
-        </p>
-      </a-form-item>
-      <a-form-item prop="objectiveAttention" label="客观题注意事项">
-        <a-input v-model="formData.objectiveAttention" allow-clear></a-input>
-      </a-form-item>
-      <a-form-item prop="subjectiveAttention" label="主观题注意事项">
-        <a-input v-model="formData.subjectiveAttention" allow-clear></a-input>
-      </a-form-item>
-    </a-form>
-
-    <template #footer>
-      <a-button type="primary" :loading="loading" @click="confirm"
-        >确认</a-button
-      >
-      <a-button @click="close">取消</a-button>
-    </template>
-  </a-modal>
-</template>
-
-<script setup lang="ts">
-  import { computed, reactive, ref } from 'vue';
-  import { Message } from '@arco-design/web-vue';
-  import type { FormInstance, FieldRule } from '@arco-design/web-vue/es/form';
-  import { saveCardRule } from '@/api/base';
-  import useLoading from '@/hooks/loading';
-  import useModal from '@/hooks/modal';
-  import useDictOption from '@/hooks/dict-option';
-
-  import { objAssign, objModifyAssign } from '@/utils/utils';
-  import { CardRuleItem, CardRuleType } from '@/api/types/base';
-  import CardTitleRuleEdit from './CardTitleRuleEdit.vue';
-
-  defineOptions({
-    name: 'ModifyCardRule',
-  });
-
-  /* modal */
-  const { visible, open, close } = useModal();
-  defineExpose({ open, close });
-
-  const defaultFormData = {
-    id: null,
-    name: '',
-    remark: '',
-    examNumberStyle: '',
-    examNumberDigit: 10,
-    paperType: 'PRINT',
-    examAbsent: true,
-    discipline: true,
-    writeSign: true,
-    requiredFields: [],
-    extendFields: [],
-    titleRule: '',
-    attention: '',
-    objectiveAttention: '',
-    subjectiveAttention: '',
-  };
-
-  const props = defineProps<{
-    rowData: CardRuleItem;
-  }>();
-  const emit = defineEmits(['modified']);
-
-  const isEdit = computed(() => !!props.rowData.id);
-  const title = computed(() => `${isEdit.value ? '编辑' : '新增'}题卡规则`);
-
-  const { optionList: examNumberStyleOptions } =
-    useDictOption('EXAM_NUMBER_STYLE');
-
-  const fieldSourses = ref([
-    {
-      code: 'courseName',
-      enable: true,
-      name: '课程名称',
-    },
-    {
-      code: 'schoolName',
-      enable: true,
-      name: '学校名称',
-    },
-  ]);
-
-  const formRef = ref<FormInstance>();
-  const formData = reactive<CardRuleType>({ ...defaultFormData });
-  const rules: Record<keyof CardRuleType, FieldRule[]> = {
-    name: [
-      {
-        required: true,
-        message: '请输入题卡规则名称',
-      },
-      {
-        max: 30,
-        message: '题卡规则名称不能超过30',
-      },
-    ],
-    examNumberStyle: [
-      {
-        required: true,
-        message: '请选择考号版式',
-      },
-    ],
-    examNumberDigit: [
-      {
-        required: false,
-        message: '请输入考号位数',
-      },
-    ],
-    paperType: [
-      {
-        required: true,
-        message: '请选择AB卷版式',
-      },
-    ],
-    titleRule: [
-      {
-        required: true,
-        message: '请输入题卡标题规则',
-      },
-    ],
-    attention: [
-      { required: true, message: '请输入注意事项' },
-      {
-        required: false,
-        validator: (value, callback) => {
-          const val = value.replace(/\n/g, '');
-          if (val.length > 200) {
-            callback('注意事项最多只能输入200个字符');
-          } else {
-            callback();
-          }
-        },
-      },
-    ],
-    objectiveAttention: [
-      {
-        required: false,
-        message: '请输入客观题注意事项',
-      },
-      {
-        max: 26,
-        message: '客观题注意事项最多只能输入26个汉字',
-      },
-    ],
-    subjectiveAttention: [
-      {
-        required: false,
-        message: '请输入主观题注意事项',
-      },
-      {
-        max: 26,
-        message: '主观题注意事项最多只能输入26个汉字',
-      },
-    ],
-  };
-
-  const examNumberStyleIsFill = computed(() => {
-    return formData.examNumberStyle === 'FILL';
-  });
-
-  function numStyleChange() {
-    formData.writeSign = formData.examNumberStyle !== 'FILL';
-    if (formData.examNumberStyle !== 'FILL') {
-      formData.examNumberDigit = 10;
-    }
-  }
-
-  /* confirm */
-  const { loading, setLoading } = useLoading();
-  async function confirm() {
-    const err = await formRef.value?.validate();
-    if (err) return;
-
-    setLoading(true);
-    const datas = objAssign(formData, {});
-    datas.requiredFields = JSON.stringify(datas.requiredFields);
-    datas.extendFields = JSON.stringify(datas.extendFields);
-    const res = await saveCardRule(datas).catch(() => false);
-    setLoading(false);
-    if (!res) return;
-    Message.success('保存成功!');
-    emit('modified', datas);
-    close();
-  }
-  /* init modal */
-  function modalBeforeOpen() {
-    objModifyAssign(formData, props.rowData);
-    formData.examNumberDigit =
-      formData.examNumberDigit || defaultFormData.examNumberDigit;
-
-    if (props.rowData.id) {
-      formData.requiredFields = JSON.parse(props.rowData.requiredFields);
-      formData.extendFields = JSON.parse(props.rowData.extendFields);
-    }
-  }
-</script>

+ 0 - 305
src/views/base/card-rule-manage/index.vue

@@ -1,305 +0,0 @@
-<template>
-  <div class="part-box is-filter">
-    <a-form
-      layout="inline"
-      :model="searchModel"
-      :label-col-props="{ span: 0, offset: 0 }"
-      :wrapper-col-props="{ span: 24, offset: 0 }"
-    >
-      <template v-if="permissions.condition_condition">
-        <a-form-item label="规则名称">
-          <a-input
-            v-model.trim="searchModel.name"
-            placeholder="规则名称"
-            allow-clear
-          ></a-input>
-        </a-form-item>
-        <a-form-item label="创建时间">
-          <select-range-datetime
-            v-model="searchModel"
-            :keys="{
-              startTime: 'createStartTime',
-              endTime: 'createEndTime',
-            }"
-          >
-          </select-range-datetime>
-        </a-form-item>
-        <a-form-item label="启用/禁用">
-          <a-select
-            v-model="searchModel.enable"
-            placeholder="启用/禁用"
-            :options="enableOption"
-            filter-option
-            allow-clear
-            :style="{ width: '140px' }"
-          >
-          </a-select>
-        </a-form-item>
-      </template>
-      <a-form-item>
-        <a-button
-          v-if="permissions.button_select"
-          type="primary"
-          @click="toPage(1)"
-          >查询</a-button
-        >
-      </a-form-item>
-    </a-form>
-    <div class="box-justify">
-      <div> </div>
-      <div>
-        <a-button v-if="permissions.button_add" type="primary" @click="toAdd"
-          >新增</a-button
-        >
-      </div>
-    </div>
-  </div>
-  <div class="part-box">
-    <a-table :columns="columns" :data="dataList" :pagination="pagination">
-      <template #index="{ rowIndex }">
-        {{ getRowIndex(rowIndex) }}
-      </template>
-      <template #examNumberStyle="{ record }">
-        {{ getExamNumberStyleLabel(record.examNumberStyle) }}
-      </template>
-      <template #enable="{ record }">
-        {{ getAbleLabel(record.enable) }}
-      </template>
-      <template #createTime="{ record }">
-        {{ timestampFilter(record.createTime) }}
-      </template>
-      <template #action="{ record }">
-        <a-button
-          v-if="permissions.link_preview"
-          class="btn-primary"
-          type="text"
-          @click="toDetail(record)"
-          >预览</a-button
-        >
-        <a-button
-          v-if="permissions.link_edit"
-          class="btn-primary"
-          type="text"
-          @click="toEdit(record)"
-          >编辑</a-button
-        >
-        <a-button
-          v-if="permissions.link_delete"
-          class="btn-danger"
-          type="text"
-          @click="toDelete(record)"
-          >删除</a-button
-        >
-        <a-button
-          v-if="permissions.link_enable"
-          :class="record.enable ? 'btn-danger' : 'btn-primary'"
-          type="text"
-          @click="toEnable(record)"
-          >{{ record.enable ? '禁用' : '启用' }}</a-button
-        >
-      </template>
-    </a-table>
-  </div>
-
-  <ModifyCardRule
-    ref="modifyCardRuleRef"
-    :row-data="curRow"
-    @modified="getList"
-  />
-</template>
-
-<script setup lang="ts">
-  import { onMounted, reactive, ref } from 'vue';
-  import { Message, Notification, TableColumnData } from '@arco-design/web-vue';
-  import {
-    deleteCardRule,
-    ableCardRule,
-    cardRuleListPage,
-    getEnums,
-    examRuleDetail,
-  } from '@/api/base';
-  import {
-    CardRuleItem,
-    ExamRuleItem,
-    ExamRuleDetailRes,
-  } from '@/api/types/base';
-  import useTable from '@/hooks/table';
-  import useDictOption from '@/hooks/dict-option';
-  import usePermission from '@/hooks/permission';
-  import { modalConfirm } from '@/utils/arco';
-  import { timestampFilter } from '@/utils/filter';
-  import { getRouterPath } from '@/utils/router-utils';
-
-  import ModifyCardRule from './ModifyCardRule.vue';
-
-  defineOptions({
-    name: 'CardRuleManage',
-  });
-  const { permissions } = usePermission();
-  const { getLabel: getExamNumberStyleLabel } =
-    useDictOption('EXAM_NUMBER_STYLE');
-  const { optionList: enableOption, getLabel: getAbleLabel } =
-    useDictOption('ABLE_TYPE');
-
-  const cardRequiredFields = ref<ExamRuleItem[]>([]);
-  const cardExtendFields = ref<ExamRuleItem[]>([]);
-  const examRule = ref<ExamRuleDetailRes>({});
-
-  async function getExamRule() {
-    // if (!this.checkPrivilege('button', 'add')) return;
-
-    const examRequiredFields = await getEnums('REQUIRED_FIELDS');
-    const crdRes = await getEnums('CARD_REQUIRED_FIELDS');
-    cardRequiredFields.value = crdRes.map((item) => {
-      return {
-        code: item.code,
-        name: item.name,
-        enable: true,
-      };
-    });
-    const cardRequiredFieldCodes = cardRequiredFields.value.map(
-      (item) => item.code
-    );
-    const extendFields = examRequiredFields.filter(
-      (field) => !cardRequiredFieldCodes.includes(field.code) && field.enable
-    );
-    examRule.value = await examRuleDetail();
-    if (!examRule.value) {
-      Notification.error({
-        title: '错误',
-        content: '请先设置通用考务规则配置',
-      });
-      return;
-    }
-
-    cardExtendFields.value = [
-      ...extendFields,
-      ...JSON.parse(examRule.value.extendFields).filter((item) => item.enable),
-    ].map((item) => {
-      return {
-        code: item.code,
-        name: item.name,
-        enable: false,
-      };
-    });
-  }
-
-  const searchModel = reactive({
-    enable: '',
-    name: '',
-    createStartTime: null,
-    createEndTime: null,
-  });
-
-  const columns: TableColumnData[] = [
-    {
-      title: '序号',
-      slotName: 'index',
-      width: 80,
-    },
-    {
-      title: '题卡规则名称',
-      dataIndex: 'name',
-    },
-    {
-      title: '考号版式',
-      dataIndex: 'examNumberStyle',
-      slotName: 'examNumberStyle',
-    },
-    {
-      title: '考号位数',
-      dataIndex: 'examNumberDigit',
-    },
-    {
-      title: '启用/禁用',
-      dataIndex: 'enable',
-      slotName: 'enable',
-      width: 100,
-    },
-    {
-      title: '创建时间',
-      dataIndex: 'createTime',
-      slotName: 'createTime',
-      width: 170,
-    },
-    {
-      title: '操作',
-      slotName: 'action',
-      width: 200,
-      fixed: 'right',
-      cellClass: 'action-column',
-    },
-  ];
-  const {
-    dataList,
-    pagination,
-    toPage,
-    getList,
-    getRowIndex,
-    deletePageLastItem,
-  } = useTable<CardRuleItem[]>(
-    cardRuleListPage,
-    searchModel,
-    permissions.button_select
-  );
-
-  // table action
-  const modifyCardRuleRef = ref(null);
-  const curRow = ref({});
-  function toAdd() {
-    curRow.value = {
-      fillNumber: examRule.value.examNumberDigit,
-      requiredFields: cardRequiredFields.value.map((item) => {
-        return { ...item };
-      }),
-      extendFields: cardExtendFields.value.map((item) => {
-        return { ...item };
-      }),
-    };
-    modifyCardRuleRef.value?.open();
-  }
-  function toEdit(row: CardRuleItem) {
-    curRow.value = row;
-    modifyCardRuleRef.value?.open();
-  }
-
-  function toDetail(row: CardRuleItem) {
-    window.open(
-      getRouterPath({
-        name: 'CardRulePreview',
-        params: {
-          cardRuleId: row.id,
-        },
-      })
-    );
-  }
-
-  async function toDelete(row: CardRuleItem) {
-    const confirmRes = await modalConfirm(
-      '提示',
-      `确定要删除题卡规则【${row.name}】吗?`
-    ).catch(() => false);
-    if (confirmRes !== 'confirm') return;
-
-    await deleteCardRule(row.id);
-    Message.success('操作成功!');
-    deletePageLastItem();
-  }
-
-  async function toEnable(row: CardRuleItem) {
-    const action = row.enable ? '禁用' : '启用';
-    const confirmRes = await modalConfirm(
-      '提示',
-      `确定要${action}题卡规则【${row.name}】吗?`
-    ).catch(() => false);
-    if (confirmRes !== 'confirm') return;
-
-    await ableCardRule({ id: row.id, enable: !row.enable });
-    Message.success('操作成功!');
-    getList();
-  }
-
-  onMounted(() => {
-    getExamRule();
-  });
-</script>

+ 0 - 288
src/views/base/common-rule/FieldTransfer.vue

@@ -1,288 +0,0 @@
-<template>
-  <div class="field-transfer">
-    <div class="field-part field-part-source">
-      <div class="field-title">
-        <a-checkbox v-model="sourceAll" @change="sourceAllChange"
-          >来源字段</a-checkbox
-        >
-      </div>
-      <div class="field-body">
-        <div v-for="item in sourceList" :key="item.code" class="field-item">
-          <a-checkbox v-model="item.checked" @change="sourceItemChange">{{
-            item.name
-          }}</a-checkbox>
-        </div>
-      </div>
-    </div>
-    <div class="field-part field-part-action">
-      <div class="action-body">
-        <a-button
-          shape="circle"
-          :disabled="!targetCheckedFields.length"
-          @click="toLeft"
-        >
-          <template #icon> <icon-left /> </template>
-        </a-button>
-        <br />
-        <a-button
-          shape="circle"
-          :disabled="!sourceCheckedFields.length"
-          @click="toRight"
-        >
-          <template #icon> <icon-right /> </template>
-        </a-button>
-      </div>
-    </div>
-    <div class="field-part field-part-source">
-      <div class="field-title">
-        <a-checkbox v-model="targetAll" @change="targetAllChange"
-          >目的字段</a-checkbox
-        >
-      </div>
-      <div
-        class="field-body"
-        @drop.prevent="dropInnerElement"
-        @dragover.prevent="dragOver($event)"
-        @dragleave.prevent
-      >
-        <div
-          v-for="item in targetList"
-          :id="`field-item-${item.code}`"
-          :key="item.code"
-          :class="[
-            'field-item',
-            {
-              'after-drop': item.code === curDropElementCode && isDragDown,
-              'before-drop': item.code === curDropElementCode && !isDragDown,
-            },
-          ]"
-          draggable="true"
-          @dragstart="($event) => dragStart($event, item)"
-          @dragend.prevent="dragEnd"
-        >
-          <a-checkbox v-model="item.checked" @change="targetItemChange">{{
-            item.name
-          }}</a-checkbox>
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-  import { IconLeft, IconRight } from '@arco-design/web-vue/es/icon';
-  import { Message } from '@arco-design/web-vue';
-  import { computed, ref, watch } from 'vue';
-
-  defineOptions({
-    name: 'FieldTransfer',
-  });
-
-  interface FiledItem {
-    code: string;
-    name: string;
-  }
-
-  type FieldListItem = FiledItem & { checked: string };
-
-  const props = withDefaults(
-    defineProps<{
-      modelValue: FiledItem[];
-      data: FiledItem[];
-    }>(),
-    {
-      modelValue: () => [],
-      data: () => [],
-    }
-  );
-  const emit = defineEmits(['update:modelValue', 'change']);
-
-  watch(
-    () => props.modelValue,
-    () => {
-      initData();
-    }
-  );
-  watch(
-    () => props.data,
-    () => {
-      initData();
-    }
-  );
-
-  // source
-  const sourceAll = ref(false);
-  const sourceList = ref<FieldListItem[]>([]);
-  const targetAll = ref(false);
-  const targetList = ref<FieldListItem[]>([]);
-
-  const targetCheckedFields = computed(() => {
-    return targetList.value.filter((item) => item.checked);
-  });
-  const sourceCheckedFields = computed(() => {
-    return sourceList.value.filter((item) => item.checked);
-  });
-
-  function initData() {
-    const fields = props.data.map((item) => {
-      return {
-        ...item,
-        checked: false,
-      };
-    });
-    const valCodes = props.modelValue.map((item) => item.code);
-    sourceList.value = fields.filter((item) => !valCodes.includes(item.code));
-    targetList.value = props.modelValue.map((item) => {
-      return { ...item, checked: false };
-    });
-  }
-  function sourceAllChange() {
-    sourceList.value.forEach((item) => {
-      item.checked = sourceAll.value;
-    });
-  }
-  function targetAllChange() {
-    targetList.value.forEach((item) => {
-      item.checked = targetAll.value;
-    });
-  }
-  function sourceItemChange() {
-    sourceAll.value = !sourceList.value.some((item) => !item.checked);
-  }
-  function targetItemChange() {
-    targetAll.value = !targetList.value.some((item) => !item.checked);
-  }
-  function toLeft() {
-    const checkedFields = targetList.value.filter((item) => item.checked);
-    if (!checkedFields.length) {
-      Message.error('请选择目的字段!');
-      return;
-    }
-
-    sourceList.value.push(
-      ...checkedFields.map((item) => {
-        return {
-          ...item,
-          checked: false,
-        };
-      })
-    );
-    targetList.value = targetList.value.filter((item) => !item.checked);
-    targetAll.value = false;
-    emitChange();
-  }
-  function toRight() {
-    const checkedFields = sourceList.value.filter((item) => item.checked);
-    if (!checkedFields.length) {
-      Message.error('请选择来源字段!');
-      return;
-    }
-
-    targetList.value.push(
-      ...checkedFields.map((item) => {
-        return {
-          ...item,
-          checked: false,
-        };
-      })
-    );
-    sourceList.value = sourceList.value.filter((item) => !item.checked);
-    sourceAll.value = false;
-    emitChange();
-  }
-  function emitChange() {
-    const targetFields = targetList.value.map((item) => {
-      return {
-        name: item.name,
-        code: item.code,
-      };
-    });
-    emit('update:modelValue', targetFields);
-    emit('change', targetFields);
-  }
-
-  // drag
-  const curDragElement = ref<FieldListItem>(null);
-  const curDropElementCode = ref('');
-  const dragStartPageY = ref(0);
-  const isDragDown = ref(false);
-
-  function getRelateElement(dom: HTMLElement) {
-    let element = null;
-    let parentNode = dom;
-    while (!element && !parentNode.className.includes('field-body')) {
-      if (!element && parentNode.id && parentNode.id.includes('field-item')) {
-        element = parentNode;
-      } else {
-        parentNode = parentNode.parentNode;
-      }
-    }
-
-    return element;
-  }
-  function getElementCode(fieldId: string) {
-    return fieldId.replace('field-item-', '');
-  }
-  function getSiblingElement(
-    fieldCode: string,
-    offset: number
-  ): FiledItem | null {
-    const pos = targetList.value.findIndex((elem) => elem.code === fieldCode);
-    return targetList.value[pos + offset] || null;
-  }
-  function moveElementToElement(
-    curElement: FieldListItem,
-    toElementCode: string,
-    isDragDownAction: boolean
-  ) {
-    const curPos = targetList.value.findIndex(
-      (elem) => elem.code === curElement.code
-    );
-    targetList.value.splice(curPos, 1);
-
-    const toPos = targetList.value.findIndex(
-      (elem) => elem.code === toElementCode
-    );
-    const offset = isDragDownAction ? 1 : 0;
-    targetList.value.splice(toPos + offset, 0, { ...curElement });
-    emitChange();
-  }
-  function dragStart(e: DragEvent, element: FieldListItem) {
-    dragStartPageY.value = e.pageY;
-    curDragElement.value = element;
-  }
-  function dragOver(e: DragEvent) {
-    // console.log(e);
-    isDragDown.value = e.pageY > dragStartPageY.value;
-    if (e.target?.className.includes('field-body')) {
-      const curDropElement = isDragDown.value
-        ? targetList.value.slice(-1)[0]
-        : targetList.value[0];
-      curDropElementCode.value = curDropElement.code;
-      return;
-    }
-
-    const elementDom = getRelateElement(e.target);
-    if (!elementDom) return;
-
-    const fieldCode = getElementCode(elementDom.id);
-    const curDropElement = getSiblingElement(fieldCode, 0);
-    curDropElementCode.value = curDropElement?.code;
-  }
-  function dropInnerElement() {
-    if (curDragElement.value.code === curDropElementCode.value) return;
-
-    // 往下:target上一个位置
-    // 往上:target下一个位置
-    moveElementToElement(
-      curDragElement.value,
-      curDropElementCode.value,
-      isDragDown.value
-    );
-  }
-  function dragEnd() {
-    curDragElement.value = null;
-    curDropElementCode.value = null;
-    dragStartPageY.value = null;
-  }
-</script>

+ 0 - 92
src/views/base/common-rule/ModifyField.vue

@@ -1,92 +0,0 @@
-<template>
-  <a-modal
-    v-model:visible="visible"
-    :width="500"
-    @before-open="modalBeforeOpen"
-  >
-    <template #title> 新增扩展字段 </template>
-    <a-form ref="formRef" :model="formData" :rules="rules" auto-label-width>
-      <a-form-item field="name" label="字段名称">
-        <a-input
-          v-model.trim="formData.name"
-          placeholder="请输入字段名称"
-          allow-clear
-        ></a-input>
-      </a-form-item>
-      <a-form-item field="code" label="字段变量">
-        <a-input
-          v-model.trim="formData.code"
-          placeholder="请输入字段变量"
-          allow-clear
-        ></a-input>
-      </a-form-item>
-    </a-form>
-
-    <template #footer>
-      <a-button type="primary" @click="confirm">确认</a-button>
-      <a-button @click="close">取消</a-button>
-    </template>
-  </a-modal>
-</template>
-
-<script setup lang="ts">
-  import { reactive, ref } from 'vue';
-  import type { FormInstance, FieldRule } from '@arco-design/web-vue/es/form';
-  import useModal from '@/hooks/modal';
-  import { objModifyAssign } from '@/utils/utils';
-
-  defineOptions({
-    name: 'ModifyField',
-  });
-
-  /* modal */
-  const { visible, open, close } = useModal();
-  defineExpose({ open, close });
-
-  const defaultFormData = {
-    name: '',
-    code: '',
-    enable: false,
-  };
-  type FormDataType = typeof defaultFormData;
-
-  const emit = defineEmits(['modified']);
-
-  const formRef = ref<FormInstance>();
-  const formData = reactive<FormDataType>({ ...defaultFormData });
-  const rules: Record<keyof FormDataType, FieldRule[]> = {
-    name: [
-      {
-        required: true,
-        message: '请输入字段名称',
-      },
-      {
-        max: 20,
-        message: '字段名称不能超过20',
-      },
-    ],
-    code: [
-      {
-        required: true,
-        message: '请输入字段变量',
-      },
-      {
-        match: /^[a-zA-Z]{3,30}$/,
-        message: '字段变量名只能由字母组成,长度在3-30之间',
-      },
-    ],
-  };
-
-  /* confirm */
-  async function confirm() {
-    const err = await formRef.value?.validate();
-    if (err) return;
-
-    emit('modified', formData);
-    close();
-  }
-  /* init modal */
-  function modalBeforeOpen() {
-    objModifyAssign(formData, {});
-  }
-</script>

+ 0 - 155
src/views/base/common-rule/RuleExam.vue

@@ -1,155 +0,0 @@
-<template>
-  <div class="rule-exam part-box">
-    <h4 class="part-box-tips">变量印刷考务字段配置:</h4>
-    <a-form :model="formData" auto-label-width>
-      <a-form-item
-        label="基础字段"
-        :content-flex="false"
-        :style="{ lineHeight: '32px' }"
-        required
-      >
-        <a-space :size="[20, 0]" wrap>
-          <a-checkbox
-            v-for="field in formData.requiredFields"
-            :key="field.code"
-            v-model="field.enable"
-            :disabled="field.disabled"
-            @change="checkRuleChange"
-            >{{ field.name }}</a-checkbox
-          >
-        </a-space>
-      </a-form-item>
-      <a-form-item label="扩展字段">
-        <div class="label-edit">
-          <div
-            v-for="field in formData.extendFields"
-            :key="field.code"
-            class="label-item"
-          >
-            <a-checkbox
-              v-model="field.enable"
-              class="label-item-content"
-              @change="checkRuleChange"
-              >{{ field.name }}</a-checkbox
-            >
-            <icon-close-circle
-              class="label-item-delete"
-              @click="deleteField(field)"
-            />
-          </div>
-          <a-button type="dashed" @click="toAddField">
-            <template #icon> <icon-plus /> </template>
-            添加</a-button
-          >
-        </div>
-      </a-form-item>
-      <a-form-item>
-        <a-button type="primary" :loading="loading" @click="submit"
-          >保存</a-button
-        >
-        <span v-if="ruleChanged" class="tips-info tips-error">(有修改)</span>
-      </a-form-item>
-    </a-form>
-
-    <!-- ModifyField -->
-    <ModifyField ref="modifyFieldRef" @modified="fieldAdded" />
-  </div>
-</template>
-
-<script setup lang="ts">
-  import { IconPlus, IconCloseCircle } from '@arco-design/web-vue/es/icon';
-  import { onMounted, reactive, ref, toRaw } from 'vue';
-  import { examRuleDetail, saveExamRule } from '@/api/base';
-  import { ExamRuleDetailRes, ExamRuleItem } from '@/api/types/base';
-  import useLoading from '@/hooks/loading';
-  import { Message } from '@arco-design/web-vue';
-  import ModifyField from './ModifyField.vue';
-
-  defineOptions({
-    name: 'RuleExam',
-  });
-
-  const defaultFormData = {
-    id: null,
-    requiredFields: [],
-    extendFields: [],
-  };
-  type FormDataType = {
-    id: string;
-    requiredFields: ExamRuleItem[];
-    extendFields: ExamRuleItem[];
-  };
-
-  const prevModalFrom = ref('');
-  const examRule = ref<ExamRuleDetailRes>({});
-  const formData = reactive<FormDataType>({ ...defaultFormData });
-
-  const ruleChanged = ref(false);
-
-  async function initData() {
-    examRule.value = await examRuleDetail();
-    formData.requiredFields = JSON.parse(examRule.value.requiredFields);
-    formData.requiredFields.sort((a) => {
-      return a.disabled ? 1 : -1;
-    });
-    if (formData.extendFields)
-      formData.extendFields = JSON.parse(examRule.value.extendFields);
-    formData.id = examRule.value.id;
-
-    if (!examRule.value.id) {
-      Message.warning('当前系统还没有考务规则,请修改保存!');
-    }
-    prevModalFrom.value = JSON.stringify(toRaw(formData));
-  }
-
-  function checkRuleExist() {
-    return !!examRule.value.id;
-  }
-
-  function checkRuleChange() {
-    ruleChanged.value = prevModalFrom.value !== JSON.stringify(toRaw(formData));
-  }
-
-  // page action
-  const modifyFieldRef = ref(null);
-  function toAddField() {
-    modifyFieldRef.value?.open();
-  }
-  function fieldAdded(field: ExamRuleItem) {
-    formData.extendFields.push({ ...field });
-    checkRuleChange();
-  }
-  function deleteField(field: ExamRuleItem) {
-    const index = formData.extendFields.findIndex(
-      (item) => item.code === field.code
-    );
-    if (index !== -1) formData.extendFields.splice(index, 1);
-    checkRuleChange();
-  }
-
-  // submit
-  const { loading, setLoading } = useLoading();
-  async function submit() {
-    if (loading.value) return;
-    setLoading(true);
-    const datas = {
-      id: formData.id,
-      requiredFields: JSON.stringify(formData.requiredFields),
-      extendFields: JSON.stringify(formData.extendFields),
-    };
-    const res = await saveExamRule(datas).catch(() => {});
-    setLoading(false);
-    if (!res) return;
-
-    formData.id = res;
-    examRule.value.id = res;
-
-    Message.success('保存成功!');
-  }
-
-  onMounted(() => {
-    initData();
-  });
-
-  defineExpose({ checkRuleExist });
-</script>

+ 0 - 120
src/views/base/common-rule/RulePackage.vue

@@ -1,120 +0,0 @@
-<template>
-  <div class="rule-package part-box">
-    <h4 class="part-box-tips">卷袋贴字段配置:</h4>
-    <a-form ref="formRef" :model="formData" :rules="rules" auto-label-width>
-      <a-form-item field="packageScope" label="卷袋贴显示字段">
-        <FieldTransfer
-          v-model="formData.packageScope"
-          :data="fieldSources"
-          @change="validateField('packageScope')"
-        />
-      </a-form-item>
-      <a-form-item>
-        <a-button type="primary" :loading="loading" @click="submit"
-          >保存</a-button
-        >
-      </a-form-item>
-    </a-form>
-  </div>
-</template>
-
-<script setup lang="ts">
-  import { onMounted, reactive, ref } from 'vue';
-  import type { FormInstance, FieldRule } from '@arco-design/web-vue/es/form';
-  import { Message } from '@arco-design/web-vue';
-
-  import {
-    ExamRuleDetailRes,
-    ExamRuleItem,
-    PackageScope,
-  } from '@/api/types/base';
-  import { examRuleDetail, saveExamRule } from '@/api/base';
-  import useLoading from '@/hooks/loading';
-  import FieldTransfer from './FieldTransfer.vue';
-
-  defineOptions({
-    name: 'RulePackage',
-  });
-
-  interface FiledItem {
-    code: string;
-    name: string;
-  }
-
-  const examRule = ref<ExamRuleDetailRes>({});
-
-  const fieldSources = ref<FiledItem[]>([]);
-  const formRef = ref<FormInstance>();
-  const formData = reactive<{ packageScope: ExamRuleItem[] }>({
-    packageScope: [],
-  });
-  const rules: Record<string, FieldRule[]> = {
-    packageScope: [
-      {
-        required: true,
-        validator: (value, callback) => {
-          if (!value || !value.length) {
-            return callback(`请选择卷袋贴显示字段`);
-          }
-
-          return callback();
-        },
-      },
-    ],
-  };
-
-  async function getFields() {
-    examRule.value = await examRuleDetail();
-    const fields: ExamRuleItem[] = [
-      ...JSON.parse(examRule.value.requiredFields),
-    ];
-    if (examRule.value.extendFields)
-      fields.push(...JSON.parse(examRule.value.extendFields));
-
-    fieldSources.value = fields
-      .filter((item) => item.enable)
-      .map((item) => {
-        return {
-          code: item.code,
-          name: item.name,
-        };
-      });
-
-    const packageScope: PackageScope = examRule.value.packageScope
-      ? JSON.parse(examRule.value.packageScope)
-      : { basic: [] };
-    formData.packageScope = packageScope.basic;
-  }
-
-  function validateField(field) {
-    formRef.value?.validateField(field, () => {});
-  }
-  // submit
-  const { loading, setLoading } = useLoading();
-  async function submit() {
-    const err = await formRef.value?.validate();
-    if (!err) return;
-
-    setLoading(true);
-    examRule.value.packageScope = JSON.stringify({
-      title: [
-        {
-          code: 'semesterName',
-          name: '学期',
-          disabled: false,
-          enable: false,
-        },
-      ],
-      basic: formData.packageScope,
-    });
-    const res = await saveExamRule(examRule.value).catch(() => {});
-    setLoading(false);
-    if (!res) return;
-
-    Message.success('保存成功!');
-  }
-
-  onMounted(() => {
-    getFields();
-  });
-</script>

+ 0 - 147
src/views/base/common-rule/RuleSign.vue

@@ -1,147 +0,0 @@
-<template>
-  <div class="rule-sign part-box">
-    <h4 class="part-box-tips">签到表字段配置:</h4>
-    <a-form ref="formRef" :model="formData" :rules="rules" auto-label-width>
-      <a-form-item field="basic" label="签到表表头字段">
-        <FieldTransfer
-          v-model="formData.basic"
-          :data="basicSources"
-          @change="validateField('basic')"
-        />
-      </a-form-item>
-      <a-form-item field="table" label="签到表考生信息字段">
-        <FieldTransfer
-          v-model="formData.table"
-          :data="tableSources"
-          @change="validateField('table')"
-        />
-      </a-form-item>
-      <a-form-item>
-        <a-button type="primary" :loading="loading" @click="submit"
-          >保存</a-button
-        >
-      </a-form-item>
-    </a-form>
-  </div>
-</template>
-
-<script setup lang="ts">
-  import { onMounted, reactive, ref, toRaw } from 'vue';
-  import type { FormInstance, FieldRule } from '@arco-design/web-vue/es/form';
-  import { Message } from '@arco-design/web-vue';
-
-  import { ExamRuleDetailRes, ExamRuleItem, SignScope } from '@/api/types/base';
-  import { examRuleDetail, saveExamRule } from '@/api/base';
-  import useLoading from '@/hooks/loading';
-  import { objModifyAssign } from '@/utils/utils';
-
-  import FieldTransfer from './FieldTransfer.vue';
-
-  defineOptions({
-    name: 'RuleSign',
-  });
-
-  interface FiledItem {
-    code: string;
-    name: string;
-  }
-
-  const examRule = ref<ExamRuleDetailRes>({});
-  const basicSources = ref<FiledItem[]>([]);
-  const tableSources = ref<FiledItem[]>([]);
-  const formRef = ref<FormInstance>();
-  const formData = reactive<SignScope>({
-    basic: [],
-    table: [],
-  });
-  const stdInfoCodes = [
-    'siteNumber',
-    'studentName',
-    'studentCode',
-    'clazzName',
-    'ticketNumber',
-    'courseName',
-  ];
-  const rules: Record<keyof SignScope, FieldRule[]> = {
-    basic: [
-      {
-        required: true,
-        validator: (value, callback) => {
-          if (!value || !value.length) {
-            return callback(`请选择签到表表头字段`);
-          }
-
-          return callback();
-        },
-      },
-    ],
-    table: [
-      {
-        required: true,
-        validator: (value, callback) => {
-          if (!value || !value.length) {
-            return callback(`请选择签到表考生信息字段`);
-          }
-
-          return callback();
-        },
-      },
-    ],
-  };
-
-  async function getFields() {
-    examRule.value = await examRuleDetail();
-    const fields: ExamRuleItem[] = [
-      ...JSON.parse(examRule.value.requiredFields),
-    ];
-    if (examRule.value.extendFields)
-      fields.push(...JSON.parse(examRule.value.extendFields));
-
-    const fieldSources = fields
-      .filter((item) => item.enable)
-      .map((item) => {
-        return {
-          code: item.code,
-          name: item.name,
-        };
-      });
-
-    basicSources.value = fieldSources.filter(
-      (item) => !stdInfoCodes.includes(item.code)
-    );
-    tableSources.value = fieldSources.filter((item) =>
-      stdInfoCodes.includes(item.code)
-    );
-    const courseInfo = fieldSources.find((item) => item.code === 'courseName');
-    if (courseInfo) basicSources.value.push({ ...courseInfo });
-
-    const signScope = examRule.value.signScope
-      ? JSON.parse(examRule.value.signScope)
-      : { basic: [], table: [] };
-
-    objModifyAssign(formData, signScope);
-  }
-
-  function validateField(field) {
-    formRef.value?.validateField(field, () => {});
-  }
-
-  // submit
-  const { loading, setLoading } = useLoading();
-  async function submit() {
-    const err = await formRef.value?.validate();
-    if (err) return;
-
-    setLoading(true);
-    examRule.value.signScope = JSON.stringify(toRaw(formData));
-    const res = await saveExamRule(examRule.value).catch(() => {});
-    setLoading(false);
-    if (!res) return;
-
-    Message.success('保存成功!');
-  }
-
-  onMounted(() => {
-    getFields();
-  });
-</script>

+ 0 - 54
src/views/base/common-rule/index.vue

@@ -1,54 +0,0 @@
-<template>
-  <div class="common-rule">
-    <div class="tab-btns">
-      <a-button
-        v-for="item in menus"
-        :key="item.id"
-        :type="item.id == curMenu.id ? 'primary' : undefined"
-        @click="selectMenu(item)"
-        >{{ item.name }}</a-button
-      >
-    </div>
-    <component
-      :is="curMenu.component"
-      v-if="permissions.button_add"
-      ref="ruleDetailRef"
-    ></component>
-  </div>
-</template>
-
-<script setup lang="ts">
-  import { Message } from '@arco-design/web-vue';
-  import { ref, shallowRef } from 'vue';
-  import usePermission from '@/hooks/permission';
-
-  import RuleExam from './RuleExam.vue';
-  import RulePackage from './RulePackage.vue';
-  import RuleSign from './RuleSign.vue';
-
-  defineOptions({
-    name: 'CommonRule',
-  });
-  const { permissions } = usePermission();
-
-  const menus = shallowRef([
-    { id: '1', name: '考务规则配置', component: RuleExam },
-    { id: '2', name: '卷袋贴字段配置', component: RulePackage },
-    { id: '3', name: '签到表字段配置', component: RuleSign },
-  ]);
-  const curMenu = shallowRef({});
-  const ruleDetailRef = ref(null);
-
-  function selectMenu(item) {
-    if (
-      curMenu.value.id === '1' &&
-      item.id !== '1' &&
-      !ruleDetailRef.value?.checkRuleExist()
-    ) {
-      Message.error('请先保存考务规则配置!');
-      return;
-    }
-    curMenu.value = item;
-  }
-  selectMenu(menus.value[0]);
-</script>

+ 0 - 133
src/views/base/organization-manage/ModifyOrganization.vue

@@ -1,133 +0,0 @@
-<template>
-  <a-modal
-    v-model:visible="visible"
-    :width="500"
-    @before-open="modalBeforeOpen"
-  >
-    <template #title> {{ title }} </template>
-    <a-form
-      ref="formRef"
-      :model="formData"
-      :rules="rules"
-      :label-col-props="{ span: 6, offset: 0 }"
-      :wrapper-col-props="{ span: 18, offset: 0 }"
-    >
-      <a-form-item label="上级机构">
-        {{ formData.parentName }}
-      </a-form-item>
-      <a-form-item field="name" label="机构名称">
-        <a-input
-          v-model.trim="formData.name"
-          placeholder="请输入机构名称"
-          allow-clear
-        ></a-input>
-      </a-form-item>
-      <a-form-item field="code" label="机构编码">
-        <a-input
-          v-model.trim="formData.code"
-          placeholder="请输入机构编码"
-          allow-clear
-        ></a-input>
-      </a-form-item>
-      <a-form-item v-if="orgTypes.length" field="type" label="机构类型">
-        <a-select v-model="formData.type" placeholder="请选择" allow-clear>
-          <a-option
-            v-for="item in orgTypes"
-            :key="item.type"
-            :value="item.type"
-            :label="item.name"
-          ></a-option>
-        </a-select>
-      </a-form-item>
-    </a-form>
-
-    <template #footer>
-      <a-button type="primary" :disabled="loading" @click="confirm"
-        >确认</a-button
-      >
-      <a-button @click="close">取消</a-button>
-    </template>
-  </a-modal>
-</template>
-
-<script setup lang="ts">
-  import { computed, reactive, ref } from 'vue';
-  import { Message } from '@arco-design/web-vue';
-  import type { FormInstance, FieldRule } from '@arco-design/web-vue/es/form';
-  import { updateOrganization } from '@/api/base';
-  import useLoading from '@/hooks/loading';
-  import useModal from '@/hooks/modal';
-  import { objAssign, objModifyAssign } from '@/utils/utils';
-
-  defineOptions({
-    name: 'ModifyOrganization',
-  });
-
-  /* modal */
-  const { visible, open, close } = useModal();
-  defineExpose({ open, close });
-
-  const defaultFormData = {
-    id: '',
-    name: '',
-    type: '',
-    code: '',
-    parentId: '',
-    parentName: '',
-    enable: true,
-  };
-  type FormDataType = typeof defaultFormData;
-  interface OrgType {
-    type: string;
-    name: string;
-  }
-
-  const props = defineProps<{
-    rowData: FormDataType;
-    orgTypes: OrgType[];
-  }>();
-  const emit = defineEmits(['modified']);
-
-  const isEdit = computed(() => !!props.rowData.id);
-  const title = computed(() => `${isEdit.value ? '编辑' : '新增'}机构`);
-
-  const formRef = ref<FormInstance>();
-  const formData = reactive<FormDataType>({ ...defaultFormData });
-  const rules: Record<keyof FormDataType, FieldRule[]> = {
-    name: [
-      {
-        required: true,
-        match: /^[0-9a-zA-Z\u4E00-\u9FA5()()]{1,100}$/,
-        message: '机构名称只能输入汉字、数字、字母和圆括号,长度不能超过100',
-      },
-    ],
-    code: [
-      {
-        required: false,
-        match: /^[0-9a-zA-Z]{1,100}$/,
-        message: '机构名称只能输入数字、字母,长度不能超过100',
-      },
-    ],
-  };
-
-  /* confirm */
-  const { loading, setLoading } = useLoading();
-  async function confirm() {
-    const err = await formRef.value?.validate();
-    if (err) return;
-
-    setLoading(true);
-    const datas = objAssign(formData, {});
-    if (!datas.type) datas.type = undefined;
-    const res = await updateOrganization(datas).catch(() => false);
-    setLoading(false);
-    if (!res) return;
-    Message.success('修改成功!');
-    emit('modified', datas);
-    close();
-  }
-  /* init modal */
-  function modalBeforeOpen() {
-    objModifyAssign(formData, props.rowData);
-  }
-</script>

+ 0 - 216
src/views/base/organization-manage/index.vue

@@ -1,216 +0,0 @@
-<template>
-  <div class="part-box">
-    <div class="box-justify">
-      <div></div>
-      <div>
-        <!-- <a-button
-          v-if="permissions.button_export"
-          type="primary"
-          icon="el-icon-download"
-          :loading="loading"
-          @click="toExportOrg"
-          >导出</a-button
-        > -->
-        <!-- <a-button
-          v-if="permissions.button_import"
-          type="primary"
-          icon="el-icon-upload2"
-          @click="toImport"
-          >导入</a-button
-        > -->
-      </div>
-    </div>
-    <a-table
-      :columns="columns"
-      :data="dataList"
-      :pagination="false"
-      row-key="id"
-      default-expand-all-rows
-      hide-expand-button-on-empty
-    >
-      <template #type="{ record }">
-        {{ getOrgTypeLabel(record.type) }}
-      </template>
-      <template #action="{ record }">
-        <template v-if="record.type === 'SCHOOL'">
-          <a-button
-            v-if="permissions.button_add"
-            class="btn-primary"
-            type="text"
-            @click="toAdd(record)"
-            >新增</a-button
-          >
-        </template>
-        <template v-else>
-          <a-button
-            v-if="record.type !== 'PRINTING_HOUSE' && permissions.link_edit"
-            class="btn-primary"
-            type="text"
-            @click="toAdd(record)"
-            >子部门</a-button
-          >
-          <a-button
-            v-if="permissions.link_edit"
-            class="btn-primary"
-            type="text"
-            @click="toEdit(record)"
-            >编辑</a-button
-          >
-          <a-button
-            v-if="permissions.link_delete"
-            class="btn-danger"
-            type="text"
-            @click="toRemove(record)"
-            >删除</a-button
-          >
-        </template>
-      </template>
-    </a-table>
-  </div>
-
-  <!-- ModifyOrganization -->
-  <ModifyOrganization
-    ref="modifyOrganizationRef"
-    :row-data="curOrg"
-    :org-types="orgTypes"
-    @modified="getList"
-  />
-</template>
-
-<script setup lang="ts">
-  import { ref } from 'vue';
-  import { Message, Modal, TableColumnData } from '@arco-design/web-vue';
-  import { organizationList, deleteOrganization } from '@/api/base';
-  import { useUserStore } from '@/store';
-  import { OrgTreeItem } from '@/api/types/base';
-  import useDictOption from '@/hooks/dict-option';
-  import usePermission from '@/hooks/permission';
-
-  import ModifyOrganization from './ModifyOrganization.vue';
-
-  defineOptions({
-    name: 'OrganizationManage',
-  });
-
-  const { permissions } = usePermission();
-  const { getLabel: getOrgTypeLabel } = useDictOption('ORG_TYPE');
-
-  const userStore = useUserStore();
-  const orgTypes = ref([{ type: 'PRINTING_HOUSE', name: '印刷室' }]);
-  const modifyOrganizationRef = ref(null);
-  const dataList = ref([]);
-  const curOrg = ref<OrgTreeItem>({});
-  const columns: TableColumnData[] = [
-    {
-      title: '机构名称',
-      dataIndex: 'name',
-    },
-    {
-      title: '机构编码',
-      dataIndex: 'code',
-      width: 100,
-    },
-    {
-      title: '机头类型',
-      dataIndex: 'type',
-      slotName: 'type',
-      width: 100,
-    },
-    {
-      title: '操作',
-      slotName: 'action',
-      width: 160,
-      align: 'right',
-      cellClass: 'action-column',
-    },
-  ];
-  async function getList() {
-    const res = await organizationList();
-    dataList.value = res || [];
-    if (dataList.value.length) {
-      dataList.value[0].children.sort((a, b) => {
-        if (a.type === 'PRINTING_HOUSE') return 1;
-        if (b.type === 'PRINTING_HOUSE') return -1;
-
-        return 0;
-      });
-    }
-  }
-  getList();
-
-  // 新增
-  function toAdd(data) {
-    if (data.type === 'PRINTING_HOUSE') return;
-
-    orgTypes.value =
-      data.type === 'SCHOOL'
-        ? [{ type: 'PRINTING_HOUSE', name: '印刷室' }]
-        : [];
-    curOrg.value = { parentId: data.id, parentName: data.name };
-    modifyOrganizationRef.value?.open();
-  }
-  function getNodeData(id: string): OrgTreeItem | null {
-    if (!id) return null;
-    let data = null;
-    const getData = (list) => {
-      if (data) return;
-      list.forEach((item) => {
-        if (data) return;
-        if (item.id === id) {
-          data = { ...item };
-          return;
-        }
-        if (item.children && item.children.length) {
-          getData(item.children);
-        }
-      });
-    };
-    getData(dataList.value);
-
-    return data;
-  }
-  function toEdit(data: OrgTreeItem) {
-    const parentData = getNodeData(data.parentId);
-    if (!parentData) return;
-
-    if (data.type !== 'PRINTING_HOUSE') {
-      orgTypes.value = [];
-    } else {
-      orgTypes.value = [{ type: 'PRINTING_HOUSE', name: '印刷室' }];
-    }
-
-    if (
-      data.type === 'PRINTING_HOUSE' ||
-      (data.type !== 'PRINTING_HOUSE' &&
-        parentData.type === 'SCHOOL' &&
-        !data.children.length)
-    ) {
-      orgTypes.value = [{ type: 'PRINTING_HOUSE', name: '印刷室' }];
-    } else {
-      orgTypes.value = [];
-    }
-
-    curOrg.value = {
-      ...data,
-      parentName: data.parentId
-        ? parentData.name
-        : userStore.curSchoolInfo?.name,
-    };
-    modifyOrganizationRef.value?.open();
-  }
-
-  function toRemove(data) {
-    Modal.confirm({
-      title: '提示',
-      content: `确定要删除【${data.name}】吗?`,
-      escToClose: false,
-      maskClosable: false,
-      closable: false,
-      async onOk() {
-        await deleteOrganization(data.id);
-        await getList();
-        Message.success('删除成功!');
-      },
-    });
-  }
-</script>

+ 0 - 480
src/views/base/print-template-manage/ModifyPrintTemplate.vue

@@ -1,480 +0,0 @@
-<template>
-  <a-modal
-    v-model:visible="visible"
-    :width="700"
-    top="10px"
-    :align-center="false"
-    @before-open="modalBeforeOpen"
-  >
-    <template #title> {{ title }} </template>
-    <a-form ref="formRef" :model="formData" :rules="rules" auto-label-width>
-      <a-form-item field="name" label="模板名称">
-        <a-input
-          v-model.trim="formData.name"
-          placeholder="建议不超过30个字,规则名称不允许重复"
-          allow-clear
-        ></a-input>
-      </a-form-item>
-      <a-form-item field="remark" label="备注">
-        <a-textarea
-          v-model.trim="formData.remark"
-          placeholder="建议不超过50个字"
-          allow-clear
-          :max-length="50"
-          show-word-limit
-        ></a-textarea>
-      </a-form-item>
-      <a-form-item field="classify" label="分类">
-        <a-select
-          v-model="formData.classify"
-          placeholder="请选择分类"
-          :options="templateClassifyOption"
-          allow-clear
-        >
-        </a-select>
-      </a-form-item>
-      <!-- SIGN -->
-      <template v-if="formData.classify === 'SIGN'">
-        <a-form-item field="testDesc" label="文字说明">
-          <a-textarea
-            v-model.trim="formData.testDesc"
-            placeholder="建议不超过500个字"
-            allow-clear
-            :max-length="500"
-            show-word-limit
-          ></a-textarea>
-        </a-form-item>
-        <a-form-item
-          field="fields"
-          label="显示字段"
-          :content-flex="false"
-          :style="{ lineHeight: '32px' }"
-        >
-          <a-space :size="[20, 0]" wrap>
-            <a-checkbox
-              v-for="field in signDatas.basic"
-              :key="field.code"
-              v-model="field.enable"
-              >{{ field.name }}</a-checkbox
-            >
-          </a-space>
-          <a-divider></a-divider>
-          <a-space :size="[20, 0]" wrap>
-            <a-checkbox
-              v-for="field in signDatas.table"
-              :key="field.code"
-              v-model="field.enable"
-              >{{ field.name }}</a-checkbox
-            >
-          </a-space>
-        </a-form-item>
-        <a-divider orientation="left">签到表页面设置</a-divider>
-        <a-form-item
-          field="diallel"
-          label="考生数据显示方式"
-          :style="{ marginBottom: 0 }"
-        >
-          <a-radio-group v-model="formData.diallel">
-            <a-radio :value="false">单列</a-radio>
-            <a-radio :value="true">双列</a-radio>
-          </a-radio-group>
-        </a-form-item>
-        <a-form-item
-          field="addBlankPage"
-          label="是否增加空白页"
-          :style="{ marginBottom: 0 }"
-        >
-          <a-radio-group v-model="formData.addBlankPage">
-            <a-radio :value="false">否</a-radio>
-            <a-radio :value="true">是</a-radio>
-          </a-radio-group>
-        </a-form-item>
-        <a-form-item
-          field="lineHeightTimes"
-          label="考生信息行间距"
-          :style="{ marginBottom: 0 }"
-        >
-          <a-radio-group v-model="formData.lineHeightTimes">
-            <a-radio :value="1">1倍</a-radio>
-            <a-radio :value="1.5">1.5倍</a-radio>
-            <a-radio :value="2">2倍</a-radio>
-          </a-radio-group>
-        </a-form-item>
-        <a-form-item
-          field="fontSize"
-          label="考生信息字号"
-          :style="{ marginBottom: 0 }"
-        >
-          <a-radio-group v-model="formData.fontSize">
-            <a-radio value="SMALL">小</a-radio>
-            <a-radio value="MEDIUM">中</a-radio>
-            <a-radio value="LARGE">大</a-radio>
-          </a-radio-group>
-        </a-form-item>
-        <a-form-item field="fieldWidth" label="信息宽度设置">
-          <a-table
-            :columns="fieldColumns"
-            :data="signTableDatas"
-            :pagination="false"
-          >
-            <template #rate="{ record }">
-              <a-input-number
-                v-model="record.rate"
-                placeholder="请输入"
-                :min="1"
-                :max="100"
-                :step="1"
-                hide-button
-              >
-                <template #suffix>%</template>
-              </a-input-number>
-            </template>
-          </a-table>
-        </a-form-item>
-      </template>
-      <!-- PACKAGE -->
-      <template v-else-if="formData.classify === 'PACKAGE'">
-        <a-form-item
-          field="fields"
-          label="显示字段"
-          :content-flex="false"
-          :style="{ lineHeight: '32px' }"
-        >
-          <a-space :size="[20, 0]" wrap>
-            <a-checkbox
-              v-for="field in packageDatas.title"
-              :key="field.code"
-              v-model="field.enable"
-              >{{ field.name }}</a-checkbox
-            >
-          </a-space>
-          <a-divider></a-divider>
-          <a-space :size="[20, 0]" wrap>
-            <a-checkbox
-              v-for="field in packageDatas.basic"
-              :key="field.code"
-              v-model="field.enable"
-              >{{ field.name }}</a-checkbox
-            >
-          </a-space>
-        </a-form-item>
-      </template>
-      <!-- CHECKIN -->
-      <template v-else>
-        <a-form-item field="attachmentId" label="上传模板文件">
-          <FileUpload
-            ref="fileUploadRef"
-            :upload-data="uploadData"
-            :upload-url="uploadUrl"
-            :format="format"
-            @upload-success="uploadSuccess"
-          />
-        </a-form-item>
-      </template>
-    </a-form>
-
-    <template #footer>
-      <a-button type="primary" :disabled="loading" @click="confirm"
-        >确认</a-button
-      >
-      <a-button @click="close">取消</a-button>
-    </template>
-  </a-modal>
-</template>
-
-<script setup lang="ts">
-  import { computed, nextTick, onMounted, reactive, ref } from 'vue';
-  import { Message, TableColumnData } from '@arco-design/web-vue';
-  import type { FormInstance, FieldRule } from '@arco-design/web-vue/es/form';
-  import {
-    attachmentDetail,
-    examRuleDetail,
-    templateDetail,
-    updateTemplate,
-  } from '@/api/base';
-  import useLoading from '@/hooks/loading';
-  import useModal from '@/hooks/modal';
-  import useDictOption from '@/hooks/dict-option';
-
-  import { calcSum, objAssign, objModifyAssign } from '@/utils/utils';
-  import {
-    AttachmentItem,
-    PackageScope,
-    PrintTemplateItem,
-    SignScope,
-  } from '@/api/types/base';
-
-  import FileUpload from '@/components/file-upload/index.vue';
-  import type { UploadSuccessData } from '@/components/file-upload/types';
-
-  defineOptions({
-    name: 'ModifyPrintTemplate',
-  });
-
-  /* modal */
-  const { visible, open, close } = useModal();
-  defineExpose({ open, close });
-
-  const { optionList: templateClassifyOption } =
-    useDictOption('TEMPLATE_CLASSIFY');
-
-  const defaultFormData = {
-    id: null,
-    name: '',
-    remark: '',
-    classify: '',
-    diallel: true,
-    addBlankPage: false,
-    lineHeightTimes: 1,
-    fontSize: '',
-    textDesc: '',
-    attachmentId: '',
-  };
-  type FormDataType = Pick<PrintTemplateItem, keyof typeof defaultFormData>;
-
-  const props = defineProps<{
-    rowData: PrintTemplateItem;
-  }>();
-  const emit = defineEmits(['modified']);
-
-  const isEdit = computed(() => !!props.rowData.id);
-  const title = computed(() => `${isEdit.value ? '编辑' : '新增'}模板`);
-
-  const packageDatas = ref<PackageScope>({ title: [], basic: [] });
-  const signDatas = ref<SignScope>({ basic: [], table: [] });
-  const PACKAGE_DATA = ref<PackageScope>({ title: [], basic: [] });
-  const SIGN_DATA = ref<SignScope>({ basic: [], table: [] });
-  const signTableDatas = computed(() => {
-    return signDatas.value.table.filter((item) => item.enable);
-  });
-  const fileUploadRef = ref(null);
-
-  /** formdata */
-  const fieldColumns: TableColumnData[] = [
-    {
-      title: '列名',
-      dataIndex: 'name',
-      width: 120,
-    },
-    {
-      title: '宽度',
-      dataIndex: 'rate',
-      slotName: 'rate',
-      width: 100,
-    },
-  ];
-
-  const attachment = ref<AttachmentItem>({});
-
-  const formRef = ref<FormInstance>();
-  const formData = reactive<FormDataType>({ ...defaultFormData });
-  const rules: Record<keyof FormDataType, FieldRule[]> = {
-    name: [
-      {
-        required: true,
-        message: '请输入模板名称',
-      },
-      {
-        max: 30,
-        message: '模板名称不能超过30个字',
-      },
-    ],
-    classify: [
-      {
-        required: true,
-        message: '请选择分类',
-      },
-    ],
-    attachmentId: [
-      {
-        required: true,
-        message: '请上传模板文件',
-      },
-    ],
-    fields: [
-      {
-        required: true,
-        validator: (value, callback) => {
-          if (formData.classify === 'PACKAGE') {
-            if (!packageDatas.value.basic.some((item) => item.enable)) {
-              return callback('请选择显示字段');
-            }
-            return callback();
-          }
-
-          if (
-            !signDatas.value.basic.some((item) => item.enable) ||
-            !signDatas.value.table.some((item) => item.enable)
-          ) {
-            return callback('请选择显示字段');
-          }
-          return callback();
-        },
-      },
-    ],
-    fieldWidth: [
-      {
-        required: true,
-        validator: (value, callback) => {
-          if (signTableDatas.value.some((item) => !item.rate)) {
-            return callback('请完成设置');
-          }
-          const rateSum = calcSum(
-            signTableDatas.value.map((item) => item.rate)
-          );
-          if (rateSum !== 100) {
-            return callback(`宽度总和需要等于100,当前总和为 ${rateSum}`);
-          }
-          return callback();
-        },
-      },
-    ],
-  };
-
-  async function getScopeField() {
-    const examRule = await examRuleDetail();
-    PACKAGE_DATA.value = examRule.packageScope
-      ? JSON.parse(examRule.packageScope)
-      : { title: [], basic: [] };
-    SIGN_DATA.value = examRule.signScope
-      ? JSON.parse(examRule.signScope)
-      : { basic: [], table: [] };
-  }
-
-  function getDefaultFieldData() {
-    packageDatas.value.title = PACKAGE_DATA.value.title.map((item) => {
-      return { ...item, enable: false };
-    });
-    packageDatas.value.basic = PACKAGE_DATA.value.basic.map((item) => {
-      return { ...item, enable: false };
-    });
-    packageDatas.value.basic.push(
-      ...[
-        {
-          code: 'paperCount',
-          name: '试卷数量',
-          enable: false,
-        },
-        {
-          code: 'examCount',
-          name: '应考人数',
-          enable: false,
-        },
-        {
-          code: 'actualExamCount',
-          name: '实考人数',
-          enable: false,
-        },
-      ]
-    );
-    signDatas.value.basic = SIGN_DATA.value.basic.map((item) => {
-      return { ...item, enable: false };
-    });
-    signDatas.value.basic.push(
-      ...[
-        {
-          code: 'examCount',
-          name: '应考人数',
-          enable: false,
-        },
-        {
-          code: 'actualExamCount',
-          name: '实考人数',
-          enable: false,
-        },
-      ]
-    );
-    signDatas.value.table = SIGN_DATA.value.table.map((item) => {
-      return { ...item, rate: undefined, enable: false };
-    });
-    signDatas.value.table.push({
-      code: 'studentSign',
-      name: '签名',
-      rate: undefined,
-      enable: true,
-    });
-  }
-  function initEditFieldData(data: PrintTemplateItem) {
-    const displayRange = data.displayRange
-      ? JSON.parse(data.displayRange)
-      : null;
-    if (!displayRange) {
-      getDefaultFieldData();
-      return;
-    }
-
-    if (data.classify === 'PACKAGE') {
-      packageDatas.value = displayRange;
-    } else {
-      signDatas.value = displayRange;
-    }
-  }
-  async function getAttachment() {
-    if (!props.rowData.attachmentId) return;
-    const data = await attachmentDetail(props.rowData.attachmentId);
-    attachment.value = data;
-
-    nextTick(() => {
-      fileUploadRef.value?.setAttachmentName(`${data.name}${data.type}`);
-    });
-  }
-
-  /* upload */
-  const uploadUrl = '/api/admin/common/file/upload';
-  const format = ['ftl', 'html', 'pdf'];
-  const uploadData = {
-    type: 'UPLOAD',
-  };
-
-  function uploadSuccess(data: UploadSuccessData) {
-    formData.attachmentId = data.response.id;
-    formRef.value?.validateField('attachmentId');
-  }
-
-  /* confirm */
-  const { loading, setLoading } = useLoading();
-  async function confirm() {
-    const err = await formRef.value?.validate();
-    if (err) return;
-
-    setLoading(true);
-    const datas = objAssign(formData, {});
-    if (formData.classify === 'PACKAGE') {
-      datas.displayRange = packageDatas.value;
-    } else if (formData.classify === 'SIGN') {
-      const signTableRates = {};
-      signTableDatas.value.forEach((item) => {
-        signTableRates[item.code] = item.rate;
-      });
-      signDatas.value.table.forEach((item) => {
-        item.rate = signTableRates[item.code] || 0;
-      });
-      datas.displayRange = signDatas.value;
-    }
-    const res = await updateTemplate(datas).catch(() => false);
-    setLoading(false);
-    if (!res) return;
-    Message.success('修改成功!');
-    emit('modified', datas);
-    close();
-  }
-  /* init modal */
-  async function modalBeforeOpen() {
-    if (props.rowData.id) {
-      const data = await templateDetail(props.rowData.id);
-      objModifyAssign(formData, data);
-      const unAttachmentTemps = ['SIGN', 'PACKAGE'];
-      if (unAttachmentTemps.includes(formData.classify)) {
-        initEditFieldData(data);
-      } else {
-        getAttachment();
-      }
-    } else {
-      objModifyAssign(formData, defaultFormData);
-    }
-  }
-
-  onMounted(() => {
-    getScopeField();
-  });
-</script>

+ 0 - 236
src/views/base/print-template-manage/index.vue

@@ -1,236 +0,0 @@
-<template>
-  <div class="part-box is-filter">
-    <a-form
-      layout="inline"
-      :model="searchModel"
-      :label-col-props="{ span: 0, offset: 0 }"
-      :wrapper-col-props="{ span: 24, offset: 0 }"
-    >
-      <template v-if="permissions.condition_condition">
-        <a-form-item label="模板名称">
-          <a-input
-            v-model.trim="searchModel.name"
-            placeholder="模板名称"
-            allow-clear
-          ></a-input>
-        </a-form-item>
-        <a-form-item label="创建时间">
-          <select-range-datetime v-model="searchModel"> </select-range-datetime>
-        </a-form-item>
-        <a-form-item label="启用/禁用">
-          <a-select
-            v-model="searchModel.enable"
-            placeholder="启用/禁用"
-            :options="enableOption"
-            filter-option
-            allow-clear
-            :style="{ width: '140px' }"
-          >
-          </a-select>
-        </a-form-item>
-      </template>
-      <a-form-item>
-        <a-button
-          v-if="permissions.button_select"
-          type="primary"
-          @click="toPage(1)"
-          >查询</a-button
-        >
-      </a-form-item>
-    </a-form>
-    <div class="box-justify">
-      <div> </div>
-      <div>
-        <a-button v-if="permissions.button_add" type="primary" @click="toAdd"
-          >新增</a-button
-        >
-      </div>
-    </div>
-  </div>
-
-  <div class="part-box">
-    <a-table :columns="columns" :data="dataList" :pagination="pagination">
-      <template #index="{ rowIndex }">
-        {{ getRowIndex(rowIndex) }}
-      </template>
-      <template #classify="{ record }">
-        {{ getTemplateClassifyLabel(record.classify) }}
-      </template>
-      <template #enable="{ record }">
-        {{ getAbleLabel(record.enable) }}
-      </template>
-      <template #createTime="{ record }">
-        {{ timestampFilter(record.createTime) }}
-      </template>
-      <template #action="{ record }">
-        <a-button
-          v-if="permissions.link_preview"
-          class="btn-primary"
-          type="text"
-          @click="toDetail(record)"
-          >预览</a-button
-        >
-        <a-button
-          v-if="permissions.link_edit"
-          class="btn-primary"
-          type="text"
-          @click="toEdit(record)"
-          >编辑</a-button
-        >
-        <a-button
-          v-if="permissions.link_enable"
-          :class="record.enable ? 'btn-danger' : 'btn-primary'"
-          type="text"
-          @click="toEnable(record)"
-          >{{ record.enable ? '禁用' : '启用' }}</a-button
-        >
-        <a-button
-          v-if="permissions.link_delete"
-          class="btn-danger"
-          type="text"
-          @click="toDelete(record)"
-          >删除</a-button
-        >
-      </template>
-    </a-table>
-  </div>
-
-  <!-- ModifyPrintTemplate -->
-  <ModifyPrintTemplate
-    ref="modifyPrintTemplateRef"
-    :row-data="curRow"
-    @modified="getList"
-  />
-</template>
-
-<script setup lang="ts">
-  import { reactive, ref } from 'vue';
-  import { Message, TableColumnData } from '@arco-design/web-vue';
-  import {
-    ableTemplate,
-    deleteTemplate,
-    templateContentView,
-    templateListPage,
-  } from '@/api/base';
-  import { PrintTemplateItem } from '@/api/types/base';
-  import useTable from '@/hooks/table';
-  import useDictOption from '@/hooks/dict-option';
-  import usePermission from '@/hooks/permission';
-  import { modalConfirm } from '@/utils/arco';
-  import { timestampFilter } from '@/utils/filter';
-
-  import ModifyPrintTemplate from './ModifyPrintTemplate.vue';
-
-  defineOptions({
-    name: 'PrintTemplateManage',
-  });
-
-  const { permissions } = usePermission();
-  const { optionList: enableOption, getLabel: getAbleLabel } =
-    useDictOption('ABLE_TYPE');
-  const { getLabel: getTemplateClassifyLabel } =
-    useDictOption('TEMPLATE_CLASSIFY');
-
-  const searchModel = reactive({
-    enable: null,
-    name: '',
-    startTime: null,
-    endTime: null,
-  });
-
-  const columns: TableColumnData[] = [
-    {
-      title: '序号',
-      slotName: 'index',
-      width: 80,
-    },
-    {
-      title: '模板名称',
-      dataIndex: 'name',
-    },
-    {
-      title: '分类',
-      dataIndex: 'classify',
-      slotName: 'classify',
-    },
-    {
-      title: '备注',
-      dataIndex: 'remark',
-    },
-    {
-      title: '启用/禁用',
-      dataIndex: 'enable',
-      slotName: 'enable',
-      width: 100,
-    },
-    {
-      title: '创建时间',
-      dataIndex: 'createTime',
-      slotName: 'createTime',
-      width: 170,
-    },
-    {
-      title: '操作',
-      slotName: 'action',
-      width: 200,
-      fixed: 'right',
-      cellClass: 'action-column',
-    },
-  ];
-  const {
-    dataList,
-    pagination,
-    toPage,
-    getList,
-    getRowIndex,
-    deletePageLastItem,
-  } = useTable<PrintTemplateItem[]>(
-    templateListPage,
-    searchModel,
-    permissions.button_select
-  );
-
-  // table action
-  const modifyPrintTemplateRef = ref(null);
-  const curRow = ref({});
-  function toAdd() {
-    curRow.value = {};
-    modifyPrintTemplateRef.value?.open();
-  }
-  function toEdit(row: PrintTemplateItem) {
-    curRow.value = row;
-    modifyPrintTemplateRef.value?.open();
-  }
-
-  async function toEnable(row: PrintTemplateItem) {
-    const action = row.enable ? '禁用' : '启用';
-    const confirmRes = await modalConfirm(
-      '提示',
-      `确定要${action}模板【${row.name}】吗?`
-    ).catch(() => false);
-    if (confirmRes !== 'confirm') return;
-
-    await ableTemplate({ id: row.id, enable: !row.enable });
-    Message.success('操作成功!');
-    getList();
-  }
-
-  async function toDelete(row: PrintTemplateItem) {
-    const confirmRes = await modalConfirm(
-      '提示',
-      `确定要删除模板【${row.name}】吗?`
-    ).catch(() => false);
-    if (confirmRes !== 'confirm') return;
-
-    await deleteTemplate(row.id);
-    Message.success('操作成功!');
-    deletePageLastItem();
-  }
-
-  async function toDetail(row) {
-    const content = await templateContentView(row.id);
-    if (!content) return;
-
-    window.open(content);
-  }
-</script>

+ 0 - 186
src/views/base/role-manage/ModifyRole.vue

@@ -1,186 +0,0 @@
-<template>
-  <a-modal v-model:visible="visible" fullscreen @before-open="modalBeforeOpen">
-    <template #title> {{ title }} </template>
-    <a-form
-      ref="formRef"
-      :model="formData"
-      :rules="rules"
-      auto-label-width
-      style="width: 500px"
-    >
-      <a-form-item field="name" label="角色名称">
-        <a-input
-          v-model.trim="formData.name"
-          placeholder="请输入角色名称"
-          allow-clear
-          :disabled="formData.defaultRole"
-        ></a-input>
-      </a-form-item>
-      <a-form-item field="interpret" label="角色描述">
-        <a-textarea
-          v-model.trim="formData.interpret"
-          placeholder="建议不超过100个字"
-          allow-clear
-        ></a-textarea>
-      </a-form-item>
-      <a-form-item label="数据权限">
-        <a-select
-          v-model="dataPermissionType"
-          placeholder="请选择数据权限"
-          :options="dataPrivilegeOption"
-          @change="dataPermissionTypeChange"
-        >
-        </a-select>
-      </a-form-item>
-    </a-form>
-    <PrivilegeSet
-      v-if="menus && menus.length"
-      ref="privilegeSetRef"
-      :menus="menus"
-    />
-
-    <template #footer>
-      <a-button type="primary" :loading="loading" @click="confirm"
-        >确认</a-button
-      >
-      <a-button @click="close">取消</a-button>
-    </template>
-  </a-modal>
-</template>
-
-<script setup lang="ts">
-  import { computed, nextTick, reactive, ref } from 'vue';
-  import { Message } from '@arco-design/web-vue';
-  import type { FormInstance, FieldRule } from '@arco-design/web-vue/es/form';
-  import { updateRole, privilegeList, roleBoundPrivileges } from '@/api/base';
-  import useLoading from '@/hooks/loading';
-  import useModal from '@/hooks/modal';
-  import useDictOption from '@/hooks/dict-option';
-  import { objAssign, objModifyAssign } from '@/utils/utils';
-
-  import PrivilegeSet from './PrivilegeSet.vue';
-
-  defineOptions({
-    name: 'ModifyRole',
-  });
-
-  /* modal */
-  const { visible, open, close } = useModal();
-  defineExpose({ open, close });
-
-  const defaultFormData = {
-    id: '',
-    name: '',
-    interpret: '',
-    privilegeIds: [],
-    dataPermissionInfo: [],
-    defaultRole: false,
-  };
-  type FormDataType = typeof defaultFormData;
-
-  const props = defineProps<{
-    rowData: FormDataType;
-  }>();
-  const emit = defineEmits(['modified']);
-
-  const isEdit = computed(() => !!props.rowData.id);
-  const title = computed(() => `${isEdit.value ? '编辑' : '新增'}角色`);
-
-  const { optionList: dataPrivilegeOption } = useDictOption(
-    'DATA_PRIVILEGE_TYPE'
-  );
-  const dataPermissionType = ref(null);
-  const menus = ref([]);
-  const privilegeSetRef = ref();
-
-  async function geMenus() {
-    const data = await privilegeList();
-    const needHideModules = ['common', 'customer'];
-    if (!data) return;
-
-    menus.value = data
-      .filter((item) => !needHideModules.includes(item.url))
-      .map((item) => {
-        item.parentId = null;
-        return item;
-      });
-  }
-  geMenus();
-
-  const formRef = ref<FormInstance>();
-  const formData = reactive<FormDataType>({ ...defaultFormData });
-  const rules: Record<keyof FormDataType, FieldRule[]> = {
-    name: [
-      {
-        required: true,
-        message: '请输入角色名称',
-      },
-      {
-        match: /^[0-9a-zA-Z\u4E00-\u9FA5]{1,20}$/,
-        message: '角色名称只能输入汉字、字母和数字,长度不能超过20',
-      },
-    ],
-    interpret: [
-      {
-        max: 100,
-        message: '角色说明最多100个字符',
-      },
-    ],
-  };
-
-  function dataPermissionTypeChange() {
-    privilegeSetRef.value?.resetdataPermissionType(dataPermissionType.value);
-  }
-
-  /* confirm */
-  const { loading, setLoading } = useLoading();
-  async function confirm() {
-    const err = await formRef.value?.validate();
-    if (err) return;
-
-    if (!privilegeSetRef.value) return;
-
-    const { privilegeIds, dataPermissionInfo } =
-      privilegeSetRef.value.getSelectedPrivileges();
-    if (!privilegeIds.length) {
-      Message.error('请设置功能权限!');
-      return;
-    }
-
-    setLoading(true);
-    const datas = objAssign(formData, {});
-    datas.privilegeIds = privilegeIds;
-    datas.dataPermissionInfo = dataPermissionInfo;
-    const res = await updateRole(datas).catch(() => false);
-    setLoading(false);
-    if (!res) return;
-    Message.success('修改成功!');
-    emit('modified', datas);
-    close();
-  }
-  /* init modal */
-  async function modalBeforeOpen() {
-    let privilegeIds = [];
-    let dataPermissionInfo = [];
-    let disabledIds = [];
-    if (props.rowData.id) {
-      objModifyAssign(formData, props.rowData);
-      const data = await roleBoundPrivileges(props.rowData.id);
-      privilegeIds = data.privilegeIds || [];
-      dataPermissionInfo = data.dataPermissionInfo || [];
-      if (props.rowData.defaultRole)
-        disabledIds = data.defaultPrivilegeIds || [];
-      formData.privilegeIds = privilegeIds;
-    } else {
-      objModifyAssign(formData, defaultFormData);
-    }
-
-    nextTick(() => {
-      privilegeSetRef.value?.buildTableData(
-        privilegeIds,
-        dataPermissionInfo,
-        disabledIds
-      );
-    });
-  }
-</script>

+ 0 - 335
src/views/base/role-manage/PrivilegeSet.vue

@@ -1,335 +0,0 @@
-<template>
-  <div class="privilege-set">
-    <table class="table">
-      <colgroup>
-        <col width="120" />
-        <col width="120" />
-        <col width="140" />
-        <col width="60" />
-        <col width="210" />
-      </colgroup>
-      <tbody>
-        <tr>
-          <th v-for="(item, index) in tableHead" :key="index">{{ item }}</th>
-        </tr>
-        <tr v-for="row in tableData" :key="row.id">
-          <td v-for="(col, cindex) in row.columns" :key="cindex">
-            <div v-if="col && col.type === 'page'">{{ col.name }}</div>
-            <div v-else-if="col && col.type === 'page-checkbox'">
-              <a-checkbox
-                v-model="row.enable"
-                :disabled="row.disabled"
-                @change="(enable) => pageSelectChange(row, enable)"
-              ></a-checkbox>
-            </div>
-            <div
-              v-else-if="
-                row.isPage && col && col.type === 'page-data-permission'
-              "
-            >
-              <a-select
-                v-model="row.dataPermissionType"
-                placeholder="请选择"
-                :disabled="row.disabled"
-                :options="dataPrivilegeOption"
-              >
-              </a-select>
-            </div>
-            <div v-else-if="col && col.type">
-              <div
-                v-for="item in col.datas"
-                :key="item.field"
-                class="cell-check-list"
-              >
-                <a-checkbox
-                  v-model="item.enable"
-                  :disabled="item.disabled"
-                  @change="(enable) => typeSelectChange(row, enable)"
-                  >{{ item.name }}</a-checkbox
-                >
-              </div>
-            </div>
-            <div v-else></div>
-          </td>
-        </tr>
-      </tbody>
-    </table>
-  </div>
-</template>
-
-<script setup lang="ts">
-  import {
-    DataPermissionTypeEnum,
-    PrivilegeTreeItem,
-    RoleBoundPrivilegesRes,
-  } from '@/api/types/base';
-  import { UserMenuItem, UserMenuPrivilegeEnum } from '@/api/types/user';
-
-  import useDictOption from '@/hooks/dict-option';
-  import { onMounted, ref } from 'vue';
-
-  defineOptions({
-    name: 'PrivilegeSet',
-  });
-
-  const props = withDefaults(
-    defineProps<{
-      menus: PrivilegeTreeItem[];
-      showPermission?: boolean;
-      disabledPermissionUrls?: string[];
-    }>(),
-    {
-      menus: () => [],
-      showPermission: true,
-      disabledPermissionUrls: () => ['TaskApplyManage', 'TaskReviewManage'],
-    }
-  );
-
-  type PrivilegeRowEnum =
-    | 'page'
-    | 'page-checkbox'
-    | 'page-data-permission'
-    | UserMenuPrivilegeEnum;
-
-  type PrivilegeRowColumnItem = Omit<UserMenuItem, UserMenuPrivilegeEnum> & {
-    disabled: boolean;
-  };
-
-  interface PrivilegeRow {
-    id: string;
-    name: string;
-    url: string;
-    enable: boolean;
-    disabled: boolean;
-    dataPermissionType: DataPermissionTypeEnum;
-    type: string;
-    parentId: string | null;
-    isPage: boolean;
-    columns: Array<{ type: PrivilegeRowEnum; datas: PrivilegeRowColumnItem[] }>;
-  }
-
-  const maxDeep = ref(0);
-  const tableData = ref<PrivilegeRow[]>([]);
-  const tableHead = ref<string[]>([]);
-
-  const { optionList: dataPrivilegeOption } = useDictOption(
-    'DATA_PRIVILEGE_TYPE'
-  );
-
-  function initData() {
-    maxDeep.value = getNavsDeep();
-    tableHead.value = buildTableHead();
-  }
-
-  function getNavsDeep() {
-    let mdp = 0;
-    const getDeep = (navs: PrivilegeTreeItem[], deep: number) => {
-      ++deep;
-      navs.forEach((nav) => {
-        if (mdp < deep) mdp = deep;
-
-        if (nav.children && nav.children.length) getDeep(nav.children, deep);
-      });
-    };
-    getDeep(props.menus, mdp);
-
-    return mdp;
-  }
-
-  function buildTableHead() {
-    let headers = [];
-    const codes = ['一', '二', '三', '四', '五', '六', '七', '八'];
-    for (let index = 0; index < maxDeep.value; index++) {
-      headers.push(`${codes[index]}级页面`);
-    }
-    headers = [...headers, '页面'];
-    if (props.showPermission) headers.push('数据权限');
-    headers = [...headers, '查询条件', '功能按钮', '列表展示', '操作列'];
-
-    return headers;
-  }
-
-  function buildTableData(
-    privilegeIds: string[],
-    dataPermissionInfo: RoleBoundPrivilegesRes['dataPermissionInfo'],
-    disabledIds: string[]
-  ) {
-    tableData.value = [];
-    const privColumnCount = props.showPermission ? 6 : 5;
-    const tableColumnCount = maxDeep.value + privColumnCount;
-    const pageSetTypes = ['conditions', 'buttons', 'lists', 'links'];
-
-    const datePermissionMap = {};
-    dataPermissionInfo.forEach((item) => {
-      datePermissionMap[item.privilegeId] = item.dataPermissionType;
-    });
-    const buildData = (navs: PrivilegeTreeItem[], deep: number) => {
-      ++deep;
-      navs.forEach((nav) => {
-        const isDisabledPermissionUrl = props.disabledPermissionUrls.includes(
-          nav.url
-        );
-        const columns = new Array(tableColumnCount);
-        columns[deep - 1] = { type: 'page', name: nav.name };
-        columns[maxDeep.value] = {
-          type: 'page-checkbox',
-        };
-        if (props.showPermission && !isDisabledPermissionUrl) {
-          columns[maxDeep.value + 1] = {
-            type: 'page-data-permission',
-          };
-        }
-
-        const isPage = pageSetTypes.some(
-          (type) => nav[type] && nav[type].length
-        );
-        const offsetPageSetInd = props.showPermission ? 2 : 1;
-        if (isPage) {
-          pageSetTypes.forEach((type: UserMenuPrivilegeEnum, index) => {
-            const datas: PrivilegeRowColumnItem[] = !nav[type]
-              ? []
-              : nav[type].map((elem) => {
-                  const data = { ...elem };
-                  data.enable = privilegeIds.includes(elem.id);
-                  data.disabled = disabledIds.includes(elem.id);
-                  return data;
-                });
-            columns[maxDeep.value + index + offsetPageSetInd] = {
-              type,
-              datas,
-            };
-          });
-        }
-
-        tableData.value.push({
-          id: nav.id,
-          name: nav.name,
-          url: nav.url,
-          enable: privilegeIds.includes(nav.id),
-          disabled: disabledIds.includes(nav.id),
-          dataPermissionType:
-            isPage && props.showPermission && !isDisabledPermissionUrl
-              ? datePermissionMap[nav.id] || 'SELF'
-              : null,
-          type: nav.type,
-          parentId: nav.parentId,
-          isPage,
-          columns,
-        });
-
-        if (nav.children && nav.children.length) buildData(nav.children, deep);
-      });
-    };
-
-    buildData(props.menus, 0);
-  }
-
-  function resetdataPermissionType(val: DataPermissionTypeEnum) {
-    tableData.value.forEach((item) => {
-      if (
-        item.isPage &&
-        !item.disabled &&
-        props.showPermission &&
-        !props.disabledPermissionUrls.includes(item.url)
-      )
-        item.dataPermissionType = val;
-    });
-  }
-
-  function getSelectedPrivileges() {
-    const privilegeIds = [];
-    const dataPermissionInfo = [];
-    tableData.value
-      .filter((row) => row.enable)
-      .forEach((row) => {
-        privilegeIds.push(row.id);
-        dataPermissionInfo.push({
-          privilegeId: row.id,
-          dataPermissionType: row.dataPermissionType,
-        });
-        row.columns.forEach((column) => {
-          if (!column.datas || !column.datas.length) return;
-
-          column.datas.forEach((item) => {
-            if (item.enable) privilegeIds.push(item.id);
-          });
-        });
-      });
-    return { privilegeIds, dataPermissionInfo };
-  }
-
-  // set change
-  function pageSelectChange(row: PrivilegeRow, enable: boolean) {
-    changRowColumnEnable(row, enable);
-    changeParentNodeSelected(row.parentId, enable);
-    changeChildrenNodeSelected(row.id, enable);
-  }
-  function typeSelectChange(row: PrivilegeRow, enable: boolean) {
-    if (!row.enable && enable) {
-      row.enable = enable;
-      changeParentNodeSelected(row.parentId, enable);
-      changeChildrenNodeSelected(row.id, enable);
-    }
-  }
-  function changRowColumnEnable(row: PrivilegeRow, enable: boolean) {
-    if (!row.isPage) return;
-    row.columns.forEach((column) => {
-      if (!column.datas || !column.datas.length) return;
-
-      column.datas.forEach((item) => {
-        item.enable = enable;
-      });
-    });
-  }
-  function changeParentNodeSelected(parentId: string | null, enable: boolean) {
-    if (!parentId) return;
-    let curParentId = parentId;
-    if (enable) {
-      while (curParentId) {
-        const curParentNode = tableData.value.find(
-          (row) => row.id === curParentId
-        );
-        curParentNode.enable = enable;
-        curParentId = curParentNode.parentId;
-        changRowColumnEnable(curParentNode, enable);
-      }
-    } else {
-      while (curParentId) {
-        const curParentNode = tableData.value.find(
-          (row) => row.id === curParentId
-        );
-        const childrenHasOneSelected = tableData.value
-          .filter((row) => row.parentId === curParentId)
-          .some((row) => row.enable);
-        curParentNode.enable = childrenHasOneSelected;
-        curParentId = curParentNode.parentId;
-        changRowColumnEnable(curParentNode, enable);
-      }
-    }
-  }
-
-  function changeChildrenNodeSelected(id: string | null, enable: boolean) {
-    if (!id) return;
-    let curIds = [id];
-    while (curIds.length) {
-      const validNodes = tableData.value.filter((row) =>
-        curIds.includes(row.parentId)
-      );
-      validNodes.forEach((row) => {
-        row.enable = enable;
-        changRowColumnEnable(row, enable);
-      });
-      curIds = validNodes.map((row) => row.id);
-    }
-  }
-
-  onMounted(() => {
-    initData();
-  });
-
-  defineExpose({
-    resetdataPermissionType,
-    getSelectedPrivileges,
-    buildTableData,
-  });
-</script>

+ 0 - 170
src/views/base/role-manage/index.vue

@@ -1,170 +0,0 @@
-<template>
-  <div class="part-box is-filter">
-    <a-form
-      layout="inline"
-      :model="searchModel"
-      :label-col-props="{ span: 0, offset: 0 }"
-      :wrapper-col-props="{ span: 24, offset: 0 }"
-    >
-      <template v-if="permissions.condition_condition">
-        <a-form-item label="角色名称">
-          <a-input
-            v-model.trim="searchModel.name"
-            placeholder="角色名称"
-            allow-clear
-          ></a-input>
-        </a-form-item>
-      </template>
-      <a-form-item>
-        <a-button
-          v-if="permissions.button_select"
-          type="primary"
-          @click="toPage(1)"
-          >查询</a-button
-        >
-      </a-form-item>
-    </a-form>
-    <div class="box-justify">
-      <div> </div>
-      <div>
-        <a-button v-if="permissions.button_add" type="primary" @click="toAdd"
-          >新增</a-button
-        >
-      </div>
-    </div>
-  </div>
-  <div class="part-box">
-    <a-table :columns="columns" :data="dataList" :pagination="pagination">
-      <template #index="{ rowIndex }">
-        {{ getRowIndex(rowIndex) }}
-      </template>
-      <template #createTime="{ record }">
-        {{ timestampFilter(record.createTime) }}
-      </template>
-      <template #action="{ record }">
-        <a-button
-          v-if="permissions.link_edit"
-          type="text"
-          class="btn-primary"
-          @click="toEdit(record)"
-          >编辑</a-button
-        >
-        <a-button
-          v-if="permissions.link_manager"
-          class="btn-primary"
-          type="text"
-          @click="toEditUser(record)"
-          >成员管理</a-button
-        >
-        <a-button
-          v-if="permissions.link_delete"
-          class="btn-danger"
-          type="text"
-          @click="toDelete(record)"
-          >删除</a-button
-        >
-      </template>
-    </a-table>
-  </div>
-
-  <ModifyRole
-    v-if="permissions.button_add || permissions.link_edit"
-    ref="modifyRoleRef"
-    :row-data="curRow"
-    @modified="getList"
-  />
-</template>
-
-<script setup lang="ts">
-  import { reactive, ref } from 'vue';
-  import { Message, TableColumnData } from '@arco-design/web-vue';
-  import { roleListPage, deleteRole } from '@/api/base';
-  import { RoleItem } from '@/api/types/base';
-  import useTable from '@/hooks/table';
-  import usePermission from '@/hooks/permission';
-
-  // import useLoading from '@/hooks/loading';
-  import { modalConfirm } from '@/utils/arco';
-  import { timestampFilter } from '@/utils/filter';
-
-  import ModifyRole from './ModifyRole.vue';
-
-  defineOptions({
-    name: 'RoleManage',
-  });
-  const { permissions } = usePermission();
-
-  const searchModel = reactive({
-    name: '',
-  });
-
-  const columns: TableColumnData[] = [
-    {
-      title: '序号',
-      slotName: 'index',
-      width: 80,
-    },
-    {
-      title: '角色名称',
-      dataIndex: 'name',
-    },
-    {
-      title: '角色说明',
-      dataIndex: 'interpret',
-    },
-    {
-      title: '创建时间',
-      dataIndex: 'createTime',
-      slotName: 'createTime',
-      width: 170,
-    },
-    {
-      title: '操作',
-      slotName: 'action',
-      width: 180,
-      fixed: 'right',
-      cellClass: 'action-column',
-    },
-  ];
-  const {
-    dataList,
-    pagination,
-    toPage,
-    getList,
-    getRowIndex,
-    deletePageLastItem,
-  } = useTable<RoleItem[]>(
-    roleListPage,
-    searchModel,
-    permissions.button_select
-  );
-
-  // table action
-  const modifyRoleRef = ref(null);
-  const curRow = ref({});
-  function toAdd() {
-    curRow.value = {};
-    modifyRoleRef.value?.open();
-  }
-  function toEdit(row: RoleItem) {
-    curRow.value = row;
-    modifyRoleRef.value?.open();
-  }
-
-  function toEditUser(row: RoleItem) {
-    curRow.value = row;
-    modifyRoleRef.value?.open();
-  }
-
-  async function toDelete(row: RoleItem) {
-    const confirmRes = await modalConfirm(
-      '提示',
-      `确定要删除角色【${row.name}】吗?`
-    ).catch(() => false);
-    if (confirmRes !== 'confirm') return;
-
-    await deleteRole(row.id);
-    Message.success('操作成功!');
-    deletePageLastItem();
-  }
-</script>

+ 0 - 175
src/views/base/user-manage/ModifyUser.vue

@@ -1,175 +0,0 @@
-<template>
-  <a-modal
-    v-model:visible="visible"
-    :width="540"
-    @before-open="modalBeforeOpen"
-  >
-    <template #title> {{ title }} </template>
-    <a-form ref="formRef" :model="formData" :rules="rules" auto-label-width>
-      <a-form-item field="loginName" label="用户名/工号">
-        <a-input
-          v-model.trim="formData.loginName"
-          placeholder="请输入用户名/工号"
-          allow-clear
-          :disabled="isEdit"
-        ></a-input>
-      </a-form-item>
-      <a-form-item field="realName" label="姓名">
-        <a-input
-          v-model.trim="formData.realName"
-          placeholder="请输入姓名"
-          allow-clear
-        ></a-input>
-      </a-form-item>
-      <a-form-item field="mobileNumber" label="手机号">
-        <a-input
-          v-model.trim="formData.mobileNumber"
-          placeholder="请输入手机号"
-          allow-clear
-        ></a-input>
-      </a-form-item>
-      <a-form-item field="roleIds" label="角色">
-        <a-select
-          v-model="formData.roleIds"
-          placeholder="请选择角色"
-          :options="roleList"
-          multiple
-          filter-option
-          allow-clear
-        >
-        </a-select>
-      </a-form-item>
-      <a-form-item field="orgId" label="所属机构">
-        <select-org v-model="formData.orgId" placeholder="选择机构">
-        </select-org>
-      </a-form-item>
-      <a-form-item>
-        <a-checkbox v-model="formData.allowManualCard"
-          >是否允许新增卡格式</a-checkbox
-        >
-      </a-form-item>
-    </a-form>
-
-    <template #footer>
-      <a-button type="primary" :disabled="loading" @click="confirm"
-        >确认</a-button
-      >
-      <a-button @click="close">取消</a-button>
-    </template>
-  </a-modal>
-</template>
-
-<script setup lang="ts">
-  import { computed, reactive, ref } from 'vue';
-  import { Message } from '@arco-design/web-vue';
-  import type { FormInstance, FieldRule } from '@arco-design/web-vue/es/form';
-  import { updateUser } from '@/api/base';
-  import useLoading from '@/hooks/loading';
-  import useModal from '@/hooks/modal';
-  import { objAssign, objModifyAssign } from '@/utils/utils';
-  import { Options } from '@/types/global';
-
-  defineOptions({
-    name: 'ModifyUser',
-  });
-
-  /* modal */
-  const { visible, open, close } = useModal();
-  defineExpose({ open, close });
-
-  const defaultFormData = {
-    id: '',
-    loginName: '',
-    realName: '',
-    mobileNumber: '',
-    allowManualCard: false,
-    roleIds: [],
-    orgId: '',
-  };
-  type FormDataType = typeof defaultFormData;
-
-  const props = defineProps<{
-    rowData: FormDataType;
-    roleList: Options[];
-  }>();
-  const emit = defineEmits(['modified']);
-
-  const isEdit = computed(() => !!props.rowData.id);
-  const title = computed(() => `${isEdit.value ? '编辑' : '新增'}用户`);
-
-  const formRef = ref<FormInstance>();
-  const formData = reactive<FormDataType>({ ...defaultFormData });
-  const rules: Record<keyof FormDataType, FieldRule[]> = {
-    loginName: [
-      {
-        required: true,
-        message: '请输入用户名',
-      },
-      {
-        max: 50,
-        message: '用户名不能超过50',
-      },
-    ],
-    realName: [
-      {
-        required: true,
-        message: '请输入姓名',
-      },
-      {
-        max: 50,
-        message: '姓名不能超过50',
-      },
-    ],
-    mobileNumber: [
-      {
-        required: false,
-        match: /^1\d{10}$/,
-        message: '请输入合适的手机号码',
-      },
-    ],
-    roleIds: [
-      {
-        required: false,
-        validator: (value, callback) => {
-          if (!value || !value.length) {
-            callback('请选择角色');
-          } else {
-            callback();
-          }
-        },
-      },
-    ],
-    orgId: [
-      {
-        required: true,
-        message: '请选择所属机构',
-      },
-    ],
-  };
-
-  /* confirm */
-  const { loading, setLoading } = useLoading();
-  async function confirm() {
-    const err = await formRef.value?.validate();
-    if (err) return;
-
-    setLoading(true);
-    const datas = objAssign(formData, {});
-    if (!datas.type) datas.type = undefined;
-    const res = await updateUser(datas).catch(() => false);
-    setLoading(false);
-    if (!res) return;
-    Message.success('修改成功!');
-    emit('modified', datas);
-    close();
-  }
-  /* init modal */
-  function modalBeforeOpen() {
-    if (props.rowData.id) {
-      objModifyAssign(formData, props.rowData);
-      formData.roleIds = props.rowData.roles?.map((item) => item.id);
-    } else {
-      objModifyAssign(formData, defaultFormData);
-    }
-  }
-</script>

+ 0 - 274
src/views/base/user-manage/index.vue

@@ -1,274 +0,0 @@
-<template>
-  <div class="part-box is-filter">
-    <a-form
-      layout="inline"
-      :model="searchModel"
-      :label-col-props="{ span: 0, offset: 0 }"
-      :wrapper-col-props="{ span: 24, offset: 0 }"
-    >
-      <template v-if="permissions.condition_condition">
-        <a-form-item label="机构">
-          <select-org
-            v-model="searchModel.orgId"
-            placeholder="选择机构"
-            clearable
-          >
-          </select-org>
-        </a-form-item>
-        <a-form-item label="关键词">
-          <a-input
-            v-model.trim="searchModel.userInfo"
-            placeholder="用户名/姓名/手机号"
-            allow-clear
-          ></a-input>
-        </a-form-item>
-        <a-form-item label="角色">
-          <a-select
-            v-model="searchModel.roleId"
-            placeholder="角色"
-            :options="roleList"
-            filter-option
-            allow-clear
-          >
-          </a-select>
-        </a-form-item>
-        <a-form-item label="启用/禁用">
-          <a-select
-            v-model="searchModel.enable"
-            placeholder="启用/禁用"
-            :options="enableOption"
-            filter-option
-            allow-clear
-            :style="{ width: '140px' }"
-          >
-          </a-select>
-        </a-form-item>
-      </template>
-      <a-form-item>
-        <a-button
-          v-if="permissions.button_select"
-          type="primary"
-          @click="toPage(1)"
-          >查询</a-button
-        >
-      </a-form-item>
-    </a-form>
-    <div class="box-justify">
-      <div>
-        <a-button
-          v-if="permissions.button_export"
-          type="primary"
-          :loading="loading"
-          @click="toExportUser"
-          >导出</a-button
-        >
-      </div>
-      <div>
-        <!-- <a-button type="success" @click="toImport">导入</a-button>
-        <a-button type="primary" @click="toDataTask">导入结果查询</a-button> -->
-        <a-button v-if="permissions.button_add" type="primary" @click="toAdd"
-          >新增</a-button
-        >
-      </div>
-    </div>
-  </div>
-  <div class="part-box">
-    <a-table :columns="columns" :data="dataList" :pagination="pagination">
-      <template #roles="{ record }">
-        {{ getRoleLabel(record.roles) }}
-      </template>
-      <template #enable="{ record }">
-        {{ getAbleLabel(record.enable) }}
-      </template>
-      <template #action="{ record }">
-        <a-button
-          v-if="permissions.link_edit"
-          type="text"
-          class="btn-primary"
-          @click="toEdit(record)"
-          >编辑</a-button
-        >
-        <a-button
-          v-if="permissions.link_enable"
-          :class="record.enable ? 'btn-danger' : 'btn-primary'"
-          type="text"
-          @click="toEnable(record)"
-          >{{ record.enable ? '禁用' : '启用' }}</a-button
-        >
-        <a-button
-          v-if="permissions.link_delete"
-          class="btn-danger"
-          type="text"
-          @click="toDelete(record)"
-          >删除</a-button
-        >
-        <a-button
-          v-if="permissions.link_reset"
-          class="btn-danger"
-          type="text"
-          @click="toResetPwd(record)"
-          >重置密码</a-button
-        >
-      </template>
-    </a-table>
-  </div>
-
-  <ModifyUser
-    v-if="permissions.button_add || permissions.link_edit"
-    ref="modifyUserRef"
-    :row-data="curRow"
-    :role-list="roleList"
-    @modified="getList"
-  />
-</template>
-
-<script setup lang="ts">
-  import { reactive, ref } from 'vue';
-  import { Message, TableColumnData } from '@arco-design/web-vue';
-  import {
-    ableUser,
-    deleteUser,
-    exportUser,
-    resetPwd,
-    userListPage,
-  } from '@/api/base';
-  import { UserItem } from '@/api/types/base';
-  import useTable from '@/hooks/table';
-  import useRole from '@/hooks/request/role';
-  import useDictOption from '@/hooks/dict-option';
-  import useLoading from '@/hooks/loading';
-  import usePermission from '@/hooks/permission';
-
-  import { useUserStore } from '@/store';
-  import { modalConfirm } from '@/utils/arco';
-  import { downloadByApi } from '@/utils/download';
-
-  import ModifyUser from './ModifyUser.vue';
-
-  defineOptions({
-    name: 'UserManage',
-  });
-
-  const { permissions } = usePermission();
-  const { optionList: enableOption, getLabel: getAbleLabel } =
-    useDictOption('ABLE_TYPE');
-  const { dataList: roleList } = useRole(true);
-
-  const getRoleLabel = (vals) => {
-    return vals.map((item) => item.name).join();
-  };
-
-  const userStore = useUserStore();
-
-  const searchModel = reactive({
-    orgId: '',
-    userInfo: '',
-    roleId: '',
-    enable: '',
-  });
-
-  const columns: TableColumnData[] = [
-    {
-      title: '用户名/工号',
-      dataIndex: 'loginName',
-    },
-    {
-      title: '姓名',
-      dataIndex: 'realName',
-    },
-    {
-      title: '手机号',
-      dataIndex: 'mobileNumber',
-    },
-    {
-      title: '所在机构',
-      dataIndex: 'orgName',
-    },
-    {
-      title: '角色',
-      dataIndex: 'roles',
-      slotName: 'roles',
-    },
-    {
-      title: '状态',
-      dataIndex: 'enable',
-      slotName: 'enable',
-    },
-    {
-      title: '操作',
-      slotName: 'action',
-      width: 220,
-      fixed: 'right',
-      cellClass: 'action-column',
-    },
-  ];
-  const { dataList, pagination, toPage, getList, deletePageLastItem } =
-    useTable<UserItem[]>(userListPage, searchModel, permissions.button_select);
-
-  // page action
-  const { loading, setLoading } = useLoading();
-  async function toExportUser() {
-    if (loading.value) return;
-
-    setLoading(true);
-    const res = await downloadByApi(() => exportUser(searchModel)).catch(
-      (e) => {
-        Message.error(e || '下载失败,请重新尝试!');
-      }
-    );
-    setLoading(false);
-    if (!res) return;
-    Message.success('下载成功!');
-  }
-
-  // table action
-  const modifyUserRef = ref(null);
-  const curRow = ref({});
-  function toAdd() {
-    curRow.value = {};
-    modifyUserRef.value?.open();
-  }
-  function toEdit(row: UserItem) {
-    curRow.value = row;
-    modifyUserRef.value?.open();
-  }
-
-  async function toEnable(row: UserItem) {
-    if (userStore.id === row.id) {
-      Message.error('不可以启用/禁用自己!');
-      return;
-    }
-    const action = row.enable ? '禁用' : '启用';
-    const confirmRes = await modalConfirm(
-      '提示',
-      `确定要${action}用户【${row.realName}】吗?`
-    ).catch(() => false);
-    if (confirmRes !== 'confirm') return;
-
-    await ableUser({ id: row.id, enable: !row.enable });
-    Message.success('操作成功!');
-    getList();
-  }
-
-  async function toDelete(row: UserItem) {
-    if (userStore.id === row.id) {
-      Message.error('不可以删除自己');
-      return;
-    }
-
-    const confirmRes = await modalConfirm(
-      '提示',
-      `确定要删除用户【${row.realName}】吗?`
-    ).catch(() => false);
-    if (confirmRes !== 'confirm') return;
-
-    await deleteUser(row.id);
-    Message.success('操作成功!');
-    deletePageLastItem();
-  }
-
-  async function toResetPwd(row: UserItem) {
-    await resetPwd(row.id);
-    Message.success('密码重置成功!');
-  }
-</script>

+ 2 - 11
src/views/login/login/ResetPwd.vue

@@ -1,5 +1,5 @@
 <template>
-  <a-modal v-model:visible="visible" title="修改密码">
+  <a-modal v-model:visible="visible" title-align="start" title="修改密码">
     <a-form ref="formRef" :model="formData" :rules="rules">
       <a-form-item field="oldPassword" label="旧密码" auto-label-width>
         <a-input-password
@@ -7,9 +7,6 @@
           placeholder="请输入旧密码"
           allow-clear
         >
-          <template #prefix>
-            <icon-lock />
-          </template>
         </a-input-password>
       </a-form-item>
       <a-form-item field="password" label="新密码">
@@ -18,9 +15,6 @@
           placeholder="请输入新密码"
           allow-clear
         >
-          <template #prefix>
-            <icon-lock />
-          </template>
         </a-input-password>
       </a-form-item>
       <a-form-item field="rePassword" label="再次密码">
@@ -29,18 +23,15 @@
           placeholder="请再次输入新密码"
           allow-clear
         >
-          <template #prefix>
-            <icon-lock />
-          </template>
         </a-input-password>
       </a-form-item>
     </a-form>
 
     <template #footer>
+      <a-button @click="close">取消</a-button>
       <a-button type="primary" :disabled="loading" @click="confirm"
         >确认</a-button
       >
-      <a-button @click="close">取消</a-button>
     </template>
   </a-modal>
 </template>

+ 6 - 1
src/views/order/order-record-manage/index.vue

@@ -231,11 +231,16 @@
   // 一键分配
   const { loading: assginLoading, setLoading: setAssignLoading } = useLoading();
   async function toAssgin() {
+    if (!searchModel.taskId) {
+      Message.error('请先选择任务!');
+      return;
+    }
+
     if (assginLoading.value) return;
     setAssignLoading(true);
 
     const res = await orderRecordAutoAssign({
-      taskId: searchModel.taskId || undefined,
+      taskId: searchModel.taskId,
     }).catch(() => false);
     setAssignLoading(false);
     if (!res) return;