CaseForm.vue 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. <template>
  2. <BasicModal
  3. v-bind="$attrs"
  4. :showFooter="true"
  5. :centered="true"
  6. @register="registerModal"
  7. @ok="handleSubmit"
  8. width="30%"
  9. >
  10. <template #title>
  11. <span> {{ isEdit ? '编辑案件' : '新增案件' }} </span>
  12. </template>
  13. <BasicForm @register="registerForm" />
  14. </BasicModal>
  15. </template>
  16. <script lang="ts" setup name="ViewsCaseForm">
  17. import { onBeforeUnmount, ref } from 'vue';
  18. import { BasicForm, FormSchema, useForm } from '@jeesite/core/components/Form';
  19. import { BasicModal, useModalInner } from '@jeesite/core/components/Modal';
  20. import { create, list, update } from '@jeesite/plat/api/case/caseApi';
  21. import type { CaseInfo, CreateCaseDTO, UpdateCaseDTO } from '@jeesite/plat/api/case/caseApi';
  22. const emit = defineEmits(['success', 'register', 'openCase']);
  23. const isEdit = ref(false);
  24. const currentCaseId = ref('');
  25. const existingCaseList = ref<CaseInfo[]>([]);
  26. const waitingAutoOpen = ref(false);
  27. const modalDestroyed = ref(false);
  28. // 是否是打开案件时触发编辑(需要设置密码后直接打开)
  29. const needPwdForOpen = ref(false);
  30. onBeforeUnmount(() => {
  31. modalDestroyed.value = true;
  32. });
  33. function safeSetModalProps(props: Record<string, any>) {
  34. if (modalDestroyed.value) return;
  35. setModalProps(props);
  36. }
  37. function safeCloseModal() {
  38. if (modalDestroyed.value) return;
  39. closeModal();
  40. }
  41. const normalizeCaseName = (value?: string) => value?.trim().toLocaleLowerCase() || '';
  42. const defaultCasePwd = '123456';
  43. const typeOptions = [
  44. '贪污',
  45. '行贿受贿',
  46. '挪用公款',
  47. '徇私枉法',
  48. '国有资产流失',
  49. '失职罪',
  50. '滥用职权',
  51. '徇私舞弊',
  52. '倒卖土地使用权',
  53. '非法转让',
  54. '违法运用资金',
  55. '危险物品肇事',
  56. ].map((item) => ({
  57. label: item,
  58. value: item,
  59. }));
  60. const addFormSchemas: FormSchema[] = [
  61. {
  62. label: '案件名称',
  63. field: 'name',
  64. component: 'Input',
  65. componentProps: {
  66. placeholder: '请输入案件名称',
  67. },
  68. rules: [
  69. { required: true, message: '请输入案件名称' },
  70. {
  71. trigger: 'blur',
  72. validator: (_rule, value) => {
  73. const normalizedName = normalizeCaseName(value);
  74. if (!normalizedName) {
  75. return Promise.resolve();
  76. }
  77. const hasDuplicateName = existingCaseList.value.some(
  78. (item) =>
  79. normalizeCaseName(item.name) === normalizedName &&
  80. String(item.id ?? '') !== String(currentCaseId.value || ''),
  81. );
  82. if (hasDuplicateName) {
  83. return Promise.reject('案件名称已存在,请重新输入');
  84. }
  85. return Promise.resolve();
  86. },
  87. },
  88. ],
  89. },
  90. {
  91. label: '案件密码',
  92. field: 'pwd',
  93. component: 'InputPassword',
  94. componentProps: {
  95. placeholder: '不填默认 123456',
  96. },
  97. rules: [
  98. {
  99. trigger: 'blur',
  100. validator: (_rule, value) => {
  101. if (isEdit.value && !value?.trim()) {
  102. return Promise.reject('请输入案件密码');
  103. }
  104. return Promise.resolve();
  105. },
  106. },
  107. ],
  108. },
  109. {
  110. label: '案件类型',
  111. field: 'type',
  112. component: 'Select',
  113. componentProps: {
  114. options: typeOptions,
  115. placeholder: '默认选择第一个案件类型',
  116. },
  117. },
  118. {
  119. label: '备注',
  120. field: 'remark',
  121. component: 'InputTextArea',
  122. componentProps: {
  123. placeholder: '请输入备注',
  124. rows: 3,
  125. },
  126. },
  127. ];
  128. const [registerForm, { resetFields, validate, setFieldsValue }] = useForm({
  129. labelWidth: 100,
  130. baseColProps: { span: 24 },
  131. schemas: addFormSchemas,
  132. showActionButtonGroup: false,
  133. });
  134. const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
  135. modalDestroyed.value = false;
  136. setModalProps({ loading: true });
  137. await resetFields();
  138. isEdit.value = data?.isEdit || false;
  139. currentCaseId.value = data?.id || '';
  140. existingCaseList.value = data?.caseList || [];
  141. waitingAutoOpen.value = false;
  142. // 获取是否需要设置密码后打开案件
  143. needPwdForOpen.value = data?.needPwdForOpen || false;
  144. if (isEdit.value && data) {
  145. setFieldsValue({
  146. name: data.name,
  147. type: data.type,
  148. remark: data.remark,
  149. pwd: '',
  150. });
  151. } else {
  152. setFieldsValue({
  153. type: typeOptions[0]?.value,
  154. });
  155. }
  156. setModalProps({ loading: false });
  157. });
  158. async function findCreatedCase(caseName: string) {
  159. const latestCaseList = await list();
  160. const normalizedName = normalizeCaseName(caseName);
  161. return [...(latestCaseList || [])]
  162. .sort((left, right) => Number(right.id || 0) - Number(left.id || 0))
  163. .find((item) => normalizeCaseName(item.name) === normalizedName);
  164. }
  165. async function handleSubmit() {
  166. try {
  167. const data = await validate();
  168. const caseName = data.name?.trim();
  169. safeSetModalProps({ confirmLoading: true });
  170. if (isEdit.value) {
  171. // 编辑模式:需要id,调用更新接口
  172. const submittedPwd = data.pwd?.trim() || '';
  173. const updateData: UpdateCaseDTO = {
  174. id: Number(currentCaseId.value),
  175. name: caseName,
  176. pwd: submittedPwd,
  177. type: data.type || typeOptions[0]?.value,
  178. remark: data.remark,
  179. };
  180. await update(updateData);
  181. // 如果是打开案件时触发的编辑,保存后直接打开案件
  182. if (needPwdForOpen.value) {
  183. emit('openCase', { id: Number(currentCaseId.value), pwd: submittedPwd });
  184. }
  185. } else {
  186. // 新增模式
  187. const createdPwd = data.pwd?.trim() || defaultCasePwd;
  188. const createdType = data.type || typeOptions[0]?.value;
  189. const createData: CreateCaseDTO = {
  190. name: caseName,
  191. pwd: createdPwd,
  192. type: createdType,
  193. remark: data.remark,
  194. };
  195. await create(createData);
  196. const createdCase = await findCreatedCase(caseName);
  197. if (createdCase?.id) {
  198. waitingAutoOpen.value = true;
  199. safeSetModalProps({ confirmLoading: true, loading: true, closable: false });
  200. emit('openCase', {
  201. id: Number(createdCase.id),
  202. pwd: createdPwd,
  203. onFinished: (success: boolean) => {
  204. waitingAutoOpen.value = false;
  205. safeSetModalProps({ confirmLoading: false, loading: false, closable: true });
  206. if (!success) {
  207. return;
  208. }
  209. safeCloseModal();
  210. emit('success', data);
  211. },
  212. });
  213. return;
  214. }
  215. safeCloseModal();
  216. emit('success', data);
  217. return;
  218. }
  219. safeCloseModal();
  220. emit('success', data);
  221. } catch (error: any) {
  222. if (error && error.errorFields) {
  223. // 表单验证错误,不做额外处理
  224. }
  225. console.log('error', error);
  226. } finally {
  227. if (!waitingAutoOpen.value) {
  228. safeSetModalProps({ confirmLoading: false, closable: true });
  229. }
  230. }
  231. }
  232. </script>
  233. <style lang="less" scoped>
  234. // 模态框底部按钮居中
  235. :deep(.jeesite-basic-modal-footer) {
  236. display: flex;
  237. justify-content: center;
  238. gap: 12px;
  239. .ant-btn {
  240. margin: 0 !important;
  241. }
  242. }
  243. </style>