crud.tsx 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  1. import { AddReq, CreateCrudOptionsProps,dict, CreateCrudOptionsRet, UserPageQuery,compute } from '@fast-crud/fast-crud';
  2. import * as api from './api';
  3. import { auth } from '/@/utils/authFunction';
  4. import { ja } from 'element-plus/es/locale';
  5. import {getBaseURL} from '/@/utils/baseUrl';
  6. import Cookies from 'js-cookie';
  7. import {request} from '/@/utils/service';
  8. import {Ref} from 'vue'
  9. export const createCrudOptions = function ({ crudExpose, dialogId,
  10. dialogVisible }: CreateCrudOptionsProps & { dialogId: Ref<number | null>; dialogVisible: Ref<boolean> }): CreateCrudOptionsRet {
  11. const pageRequest = async (query: UserPageQuery) => {
  12. return await api.GetList(query);
  13. };
  14. const editRequest = async ({ form, row }: EditReq) => {
  15. form.id = row.id;
  16. return await api.UpdateObj(form);
  17. };
  18. const delRequest = async ({ row }: DelReq) => {
  19. return await api.DelObj(row.id);
  20. };
  21. const addRequest = async ({ form }: AddReq) => {
  22. return await api.AddObj(form);
  23. };
  24. return {
  25. crudOptions: {
  26. request: {
  27. pageRequest,
  28. addRequest,
  29. editRequest,
  30. delRequest,
  31. },
  32. form:{
  33. wrapper: {
  34. buttons: {
  35. ok:{
  36. text:'提交',
  37. show:compute((row) => {
  38. return row.mode !=='view'
  39. })
  40. }
  41. }
  42. }
  43. },
  44. actionbar: {
  45. buttons: {
  46. add: {
  47. show: auth('area:Create'),
  48. },
  49. },
  50. },
  51. toolbar:{
  52. show:false,
  53. },
  54. rowHandle:{
  55. fixed: 'right',
  56. width: 220,
  57. buttons:{
  58. remove:{
  59. show:true,
  60. },
  61. edit:{
  62. show:compute(({ row }) => {
  63. return row.status !== 3;
  64. }),
  65. },
  66. updateStatus: {
  67. text: '修改状态',
  68. show: false,
  69. order: 99,
  70. type: 'primary',
  71. click({ row }) {
  72. dialogId.value = row.id
  73. dialogVisible.value = true
  74. }
  75. }
  76. }
  77. },
  78. pagination: {
  79. show: true,
  80. },
  81. columns: {
  82. _index: {
  83. title: '序号',
  84. form: { show: false },
  85. column: {
  86. type: 'index',
  87. align: 'center',
  88. width: '70px',
  89. columnSetDisabled: true, //禁止在列设置中选择
  90. },
  91. },
  92. search:{
  93. title: '关键字搜索',
  94. search: { show: true,type: 'input', },
  95. type: 'input',
  96. form: {
  97. component: { placeholder: '请输入' },
  98. show:false},
  99. column: {show:false}
  100. },
  101. damage_no: {
  102. title: '编号',
  103. search: {
  104. show: false,
  105. },
  106. treeNode: true,
  107. type: 'input',
  108. column: {
  109. show:false,
  110. minWidth: 120,
  111. },
  112. form: {
  113. show:false,
  114. // rules: [
  115. // // 表单校验规则
  116. // // { required: true, message: '名称必填项' },
  117. // ],
  118. component: {
  119. placeholder: '请输入编号',
  120. onChange: async (context: any) => {
  121. // 当选择设备时,自动回填设备编号和设备名称
  122. console.log("onChange context:", context);
  123. }
  124. },
  125. },
  126. viewForm:{
  127. component: { placeholder: '' },
  128. rules: [{ required: true, message: '' }],
  129. }
  130. },
  131. device_code:{
  132. title: '设备编号',
  133. type: 'input',
  134. column: {
  135. show:true,
  136. minWidth: 120,
  137. },
  138. form: {
  139. show:true,
  140. component: { placeholder: '请填写设备编号',
  141. onBlur: async (event: any) => {
  142. // 当输入框失去焦点时,根据编号搜索设备信息
  143. const deviceCode = event.target.value?.trim();
  144. console.log("onBlur deviceCode:", deviceCode);
  145. if (!deviceCode) return;
  146. try {
  147. // 调用API搜索设备信息
  148. const response = await request({
  149. url: `/api/system/device/?code=${encodeURIComponent(deviceCode)}`,
  150. method: 'get'
  151. });
  152. console.log("设备搜索响应:", response);
  153. if (response.code === 2000 && response.data && response.data.length > 0) {
  154. const deviceData = response.data[0]; // 取第一个匹配的设备
  155. console.log("找到设备:", deviceData);
  156. // 使用 crudExpose 来设置表单数据
  157. const formData = crudExpose.getFormData();
  158. formData.device = deviceData.id; // 设置设备ID
  159. formData.device_code = deviceData.code; // 设置设备编号
  160. formData.device_name = deviceData.name; // 设置设备名称
  161. crudExpose.setFormData(formData);
  162. } else {
  163. console.log("未找到匹配的设备");
  164. // 可以在这里显示提示信息
  165. }
  166. } catch (error) {
  167. console.error("搜索设备信息失败:", error);
  168. }
  169. }
  170. },
  171. rules: [{ required: true, message: '请填写设备编号' }],
  172. },
  173. editForm:{
  174. component: { disabled: true },
  175. },
  176. viewForm:{
  177. component: { placeholder: '' },
  178. rules: [{ required: true, message: '' }],
  179. }
  180. },
  181. device:{
  182. title: '设备名称',
  183. type: 'dict-select',
  184. column: {
  185. show:false,
  186. minWidth: 120,
  187. },
  188. dict: dict({
  189. url: '/api/system/device/?has_inventory=1',
  190. value: 'id',
  191. label: 'name',
  192. }),
  193. form: {
  194. component: { placeholder: '请选择设备名称',
  195. onChange: async (context: any) => {
  196. // 当选择设备时,自动回填设备编号和设备名称
  197. console.log("onChange context:", context);
  198. // 获取选中的设备ID
  199. const selectedDeviceId = context;
  200. if (!selectedDeviceId) return;
  201. try {
  202. // 通过API获取设备详情
  203. const response = await request({
  204. url: `/api/system/device/${selectedDeviceId}/`,
  205. method: 'get'
  206. });
  207. console.log("response::::",response)
  208. if (response.code==2000) {
  209. const deviceData = response.data;
  210. console.log("设备数据:", deviceData);
  211. // 使用 crudExpose 来设置表单数据
  212. const formData = crudExpose.getFormData();
  213. formData.device_code = deviceData.code;
  214. formData.device_name = deviceData.name;
  215. crudExpose.setFormData(formData);
  216. }
  217. } catch (error) {
  218. console.error("获取设备信息失败:", error);
  219. }
  220. },
  221. },
  222. rules: [{ required: true, message: '请填写设备名称' }],
  223. },
  224. editForm:{
  225. component: { disabled: true },
  226. },
  227. viewForm:{
  228. component: { placeholder: '' },
  229. rules: [{ required: true, message: '' }],
  230. }
  231. },
  232. device_name:{
  233. title: '设备名称',
  234. type: 'input',
  235. column: {
  236. show:true,
  237. minWidth: 120,
  238. },
  239. form: {
  240. show:false,
  241. component: { placeholder: '请填写设备名称' },
  242. rules: [{ required: true, message: '请填写设备名称' }],
  243. },
  244. viewForm:{
  245. component: { placeholder: '' },
  246. rules: [{ required: true, message: '' }],
  247. }
  248. },
  249. quantity:{
  250. title: '维修数量',
  251. type: 'number',
  252. column: {
  253. minWidth: 120,
  254. },
  255. form: {
  256. component: {
  257. placeholder: '请填写维修数量',
  258. min: 0,
  259. precision: 0
  260. },
  261. rules: [
  262. { required: false, message: '请填写维修数量' },
  263. {
  264. type: 'number',
  265. min: 0,
  266. message: '维修数量不能为负数',
  267. trigger: 'blur'
  268. },
  269. {
  270. validator: (rule: any, value: any, callback: any) => {
  271. if (value !== null && value !== undefined && value !== '') {
  272. if (!Number.isInteger(Number(value)) || Number(value) < 0) {
  273. callback(new Error('维修数量必须为正整数'));
  274. } else {
  275. callback();
  276. }
  277. } else {
  278. callback();
  279. }
  280. },
  281. trigger: 'blur'
  282. }
  283. ],
  284. },
  285. editForm:{
  286. component: { disabled: true },
  287. },
  288. valueResolve({ form, value }) {
  289. form.quantity = Number(value);
  290. },
  291. viewForm:{
  292. component: { placeholder: '' },
  293. rules: [{ required: true, message: '' }],
  294. }
  295. },
  296. damage_type:{
  297. title: '维修类型',
  298. type: 'dict-select',
  299. dict: dict({
  300. data: [
  301. // { label: '报废', value: 0 },
  302. { label: '维修', value: 1 },
  303. ],
  304. }),
  305. column: {
  306. show:false,
  307. minWidth: 120,
  308. },
  309. form: {
  310. value:1,
  311. show:false,
  312. component: { placeholder: '请填写排序'},
  313. rules: [{ required: false, message: '请填写排序' }],
  314. },
  315. editForm:{
  316. component: { disabled: true },
  317. },
  318. viewForm:{
  319. component: { placeholder: '' },
  320. rules: [{ required: true, message: '' }],
  321. }
  322. },
  323. estimated_loss:{
  324. title: '维修费用(元)',
  325. type: 'number',
  326. column: {
  327. minWidth: 120,
  328. show:compute(({ form }) => {
  329. // 只有当选择了胜任力标签时才显示配置
  330. return form && form.damage_type === 1;
  331. })
  332. },
  333. form: {
  334. show:false,
  335. component: {
  336. placeholder: '请填写维修费用',
  337. min: 0,
  338. precision: 2
  339. },
  340. rules: [
  341. { required: false, message: '请填写维修费用' },
  342. {
  343. type: 'number',
  344. min: 0,
  345. message: '维修费用不能为负数',
  346. trigger: 'blur'
  347. },
  348. {
  349. validator: (rule: any, value: any, callback: any) => {
  350. if (value !== null && value !== undefined && value !== '') {
  351. const numValue = Number(value);
  352. if (isNaN(numValue) || numValue < 0) {
  353. callback(new Error('维修费用必须为有效的正数'));
  354. } else if (numValue > 999999.99) {
  355. callback(new Error('维修费用不能超过999999.99元'));
  356. } else {
  357. callback();
  358. }
  359. } else {
  360. callback();
  361. }
  362. },
  363. trigger: 'blur'
  364. }
  365. ],
  366. show:compute(({ form }) => {
  367. // 只有当选择了胜任力标签时才显示配置
  368. return form && form.damage_type === 1;
  369. })
  370. },
  371. editForm:{
  372. show:compute(({ form }) => {
  373. // 只有当选择了胜任力标签时才显示配置
  374. return form && form.status == 3;
  375. }),
  376. component: {
  377. placeholder: '请填写维修费用',
  378. min: 0,
  379. precision: 2
  380. },
  381. rules: [
  382. { required: compute(({ form }) => {
  383. return form && form.status === 3;
  384. }), message: '请填写维修费用' },
  385. {
  386. type: 'number',
  387. min: 0,
  388. message: '维修费用不能为负数',
  389. trigger: 'blur'
  390. },
  391. {
  392. validator: (rule: any, value: any, callback: any) => {
  393. if (value !== null && value !== undefined && value !== '') {
  394. const numValue = Number(value);
  395. if (isNaN(numValue) || numValue < 0) {
  396. callback(new Error('维修费用必须为有效的正数'));
  397. } else if (numValue > 999999.99) {
  398. callback(new Error('维修费用不能超过999999.99元'));
  399. } else {
  400. callback();
  401. }
  402. } else {
  403. callback();
  404. }
  405. },
  406. trigger: 'blur'
  407. }
  408. ],
  409. },
  410. addForm:{
  411. show:false,
  412. },
  413. viewForm:{
  414. component: { placeholder: '' },
  415. rules: [{ required: true, message: '' }],
  416. show:compute(({ form }) => {
  417. // 只有当选择了胜任力标签时才显示配置
  418. return form && form.damage_type === 1;
  419. })
  420. },
  421. valueResolve({ form, value }) {
  422. form.estimated_loss = Number(value);
  423. }
  424. },
  425. responsible_person:{
  426. title: '维修人',
  427. type: 'input',
  428. column: {
  429. minWidth: 120,
  430. },
  431. form: {
  432. show:false,
  433. component: { placeholder: '请填写维修人姓名' },
  434. rules: [
  435. { required: false, message: '请填写维修人' },
  436. { min: 2, max: 20, message: '维修人姓名长度应在2-20个字符之间', trigger: 'blur' },
  437. {
  438. validator: (rule: any, value: any, callback: any) => {
  439. if (value && value.trim()) {
  440. const nameRegex = /^[\u4e00-\u9fa5a-zA-Z\s]+$/;
  441. if (!nameRegex.test(value.trim())) {
  442. callback(new Error('维修人姓名只能包含中文、英文字母和空格'));
  443. } else {
  444. callback();
  445. }
  446. } else {
  447. callback();
  448. }
  449. },
  450. trigger: 'blur'
  451. }
  452. ],
  453. },
  454. editForm:{
  455. show:compute(({ form }) => {
  456. // 只有当选择了胜任力标签时才显示配置
  457. return form && form.status == 3;
  458. }),
  459. component: { placeholder: '请填写维修人姓名' },
  460. rules: [
  461. { required: compute(({ form }) => {
  462. return form && form.status === 2;
  463. }), message: '请填写维修人' },
  464. { min: 2, max: 20, message: '维修人姓名长度应在2-20个字符之间', trigger: 'blur' },
  465. {
  466. validator: (rule: any, value: any, callback: any) => {
  467. if (value && value.trim()) {
  468. const nameRegex = /^[\u4e00-\u9fa5a-zA-Z\s]+$/;
  469. if (!nameRegex.test(value.trim())) {
  470. callback(new Error('维修人姓名只能包含中文、英文字母和空格'));
  471. } else {
  472. callback();
  473. }
  474. } else {
  475. callback();
  476. }
  477. },
  478. trigger: 'blur'
  479. }
  480. ],
  481. },
  482. viewForm:{
  483. component: { placeholder: '' },
  484. rules: [{ required: true, message: '' }],
  485. }
  486. },
  487. responsible_phone:{
  488. title: '维修人电话',
  489. type: 'input',
  490. column: {
  491. show:true,
  492. minWidth: 120,
  493. },
  494. form: {
  495. show:false,
  496. component: { placeholder: '请填写维修人电话' },
  497. rules: [
  498. { required: false, message: '请填写维修人电话' },
  499. {
  500. validator: (rule: any, value: any, callback: any) => {
  501. if (value && value.trim()) {
  502. const phoneRegex = /^1[3-9]\d{9}$|^0\d{2,3}-?\d{7,8}$|^400-?\d{3}-?\d{4}$/;
  503. if (!phoneRegex.test(value.trim())) {
  504. callback(new Error('请输入正确的手机号码或固定电话号码'));
  505. } else {
  506. callback();
  507. }
  508. } else {
  509. callback();
  510. }
  511. },
  512. trigger: 'blur'
  513. }
  514. ],
  515. },
  516. editForm:{
  517. show:compute(({ form }) => {
  518. // 只有当选择了胜任力标签时才显示配置
  519. return form && form.status == 3;
  520. }),
  521. component: { placeholder: '请填写维修人电话' },
  522. rules: [
  523. { required: compute(({ form }) => {
  524. return form && form.status === 2;
  525. }), message: '请填写维修人电话' },
  526. {
  527. validator: (rule: any, value: any, callback: any) => {
  528. if (value && value.trim()) {
  529. const phoneRegex = /^1[3-9]\d{9}$|^0\d{2,3}-?\d{7,8}$|^400-?\d{3}-?\d{4}$/;
  530. if (!phoneRegex.test(value.trim())) {
  531. callback(new Error('请输入正确的手机号码或固定电话号码'));
  532. } else {
  533. callback();
  534. }
  535. } else {
  536. callback();
  537. }
  538. },
  539. trigger: 'blur'
  540. }
  541. ],
  542. },
  543. viewForm:{
  544. show:true,
  545. component: { placeholder: '' },
  546. rules: [{ required: true, message: '' }],
  547. }
  548. },
  549. reporter_name:{
  550. title: '负责人',
  551. type: 'input',
  552. column: {
  553. minWidth: 120,
  554. },
  555. form: {
  556. show:true,
  557. component: { placeholder: '请填写负责人' },
  558. rules: [{ required: false, message: '请填写负责人' }],
  559. },
  560. viewForm:{
  561. component: { placeholder: '' },
  562. rules: [{ required: true, message: '' }],
  563. }
  564. },
  565. status:{
  566. search:{
  567. show:true
  568. },
  569. title: '维修状态',
  570. type: 'dict-select',
  571. column: {
  572. show:true,
  573. minWidth: 120,
  574. },
  575. dict: dict({
  576. data: [
  577. { label: '待维修', value: 1 ,color: "warning"},
  578. { label: '维修中', value: 2 ,color: "primary"},
  579. { label: '维修完成', value: 3,color: "success" },
  580. ],
  581. }),
  582. form: {
  583. show:false,
  584. component: { placeholder: '请选择维修状态' },
  585. rules: [{ required: false, message: '请选择维修状态' }],
  586. },
  587. editForm:{
  588. show:true,
  589. component: { placeholder: '请选择维修状态' },
  590. rules: [{ required: true, message: '请选择维修状态' }],
  591. },
  592. viewForm:{
  593. show:true,
  594. component: { placeholder: '' },
  595. rules: [{ required: true, message: '' }],
  596. }
  597. },
  598. /* status_display:{
  599. title: '维修状态',
  600. type: 'input',
  601. column: {
  602. minWidth: 120,
  603. },
  604. form: {
  605. show:false,
  606. component: { placeholder: '请填写负责人' },
  607. rules: [{ required: false, message: '请填写负责人' }],
  608. },
  609. viewForm:{
  610. component: { placeholder: '' },
  611. rules: [{ required: true, message: '' }],
  612. }
  613. }, */
  614. remark:{
  615. title: '备注',
  616. type: 'input',
  617. column: {
  618. minWidth: 120,
  619. },
  620. form: {
  621. show:true,
  622. component: { placeholder: '请填写备注' },
  623. rules: [{ required: false, message: '请填写备注' }],
  624. },
  625. viewForm:{
  626. component: { placeholder: '' },
  627. rules: [{ required: true, message: '' }],
  628. }
  629. },
  630. damage_reason:{
  631. title: '维修原因',
  632. type: 'textarea',
  633. column: {
  634. minWidth: 120,
  635. },
  636. form: {
  637. component: { placeholder: '请填写维修原因' },
  638. rules: [{ required: false, message: '请填写维修原因' }],
  639. },
  640. viewForm:{
  641. component: { placeholder: '' },
  642. rules: [{ required: true, message: '' }],
  643. }
  644. },
  645. repair_result:{
  646. title: '维修结果',
  647. type: 'textarea',
  648. column: {
  649. minWidth: 120,
  650. },
  651. form: {
  652. show:false,
  653. component: { placeholder: '请填写维修结果' },
  654. rules: [{ required: false, message: '请填写维修结果' }],
  655. },
  656. editForm:{
  657. show:compute(({ form }) => {
  658. // 只有当选择了胜任力标签时才显示配置
  659. return form && form.status == 3;
  660. }),
  661. component: { placeholder: '请填写维修结果' },
  662. rules: [{ required: false, message: '请填写维修结果' }],
  663. },
  664. viewForm:{
  665. component: { placeholder: '' },
  666. rules: [{ required: true, message: '' }],
  667. }
  668. },
  669. damage_images:{
  670. title: '附件',
  671. type: 'image-uploader',
  672. column: {
  673. minWidth: 120,
  674. },
  675. form: {
  676. show: auth('image:upload'),
  677. component: {
  678. uploader: {
  679. type: 'form',
  680. limit: 1,
  681. action: '/api/system/device/upload-image/',
  682. accept: ".jpg,.png",
  683. uploadRequest: async ({ action, file, onProgress }) => {
  684. const token = Cookies.get('token');
  685. const data = new FormData();
  686. data.append("image", file);
  687. return await request({
  688. url: action,
  689. method: "post",
  690. timeout: 60000,
  691. headers: {
  692. "Content-Type": "multipart/form-data",
  693. "Authorization": token ? `JWT ${token}` : ''
  694. },
  695. data,
  696. onUploadProgress: (p) => {
  697. onProgress({ percent: Math.round((p.loaded / p.total) * 100) });
  698. }
  699. });
  700. },
  701. successHandle(ret) {
  702. // eslint-disable-next-line no-console
  703. // console.log("ret.data.image_url:::",ret.data.image_url);
  704. return {
  705. url: getBaseURL(ret.data.image_url),
  706. key: ret.data.id,
  707. ...ret.data
  708. };
  709. },
  710. }
  711. },
  712. },
  713. valueBuilder({ row, key }) {
  714. return row[key] ? [row[key]] : [];
  715. },
  716. valueResolve({ form, key }) {
  717. // eslint-disable-next-line no-console
  718. console.log("form[key]:::",form[key]);
  719. form[key] = Array.isArray(form[key]) ? form[key][0] : form[key];
  720. },
  721. viewForm:{
  722. component: { placeholder: '' },
  723. rules: [{ required: true, message: '' }],
  724. }
  725. },
  726. repair_start_time:{
  727. title: '维修开始时间',
  728. type: 'input',
  729. column: {
  730. minWidth: 120,
  731. },
  732. form: {
  733. show:false,
  734. component: { placeholder: '创建时间' },
  735. rules: [{ required: false, message: '创建时间' }],
  736. },
  737. viewForm:{
  738. component: { placeholder: '' },
  739. rules: [{ required: true, message: '' }],
  740. }
  741. },
  742. repair_end_time:{
  743. title: '维修完成时间',
  744. type: 'input',
  745. column: {
  746. minWidth: 120,
  747. },
  748. form: {
  749. show:false,
  750. component: {
  751. placeholder: '创建时间',
  752. valueFormat: "YYYY-MM-DD HH:mm:ss",
  753. },
  754. rules: [{ required: false, message: '创建时间' }],
  755. },
  756. viewForm:{
  757. component: { placeholder: '' },
  758. rules: [{ required: true, message: '' }],
  759. }
  760. },
  761. report_time:{
  762. title: '创建时间',
  763. type: 'input',
  764. column: {
  765. minWidth: 120,
  766. },
  767. form: {
  768. show:false,
  769. component: { placeholder: '创建时间' },
  770. rules: [{ required: false, message: '创建时间' }],
  771. },
  772. viewForm:{
  773. component: { placeholder: '' },
  774. rules: [{ required: true, message: '' }],
  775. }
  776. },
  777. },
  778. },
  779. };
  780. };