detail.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. <template>
  2. <div class="modal">
  3. <el-dialog
  4. v-model="dialogVisible"
  5. :title="dialogTitle"
  6. :width="modalConfig.dialogWidth || '80%'"
  7. center
  8. @close="handleExcel(ruleFormRef)"
  9. :close-on-click-modal="false"
  10. >
  11. <template #header>
  12. <pageTitle :title="dialogTitle"></pageTitle>
  13. </template>
  14. <div class="form">
  15. <el-form
  16. ref="ruleFormRef"
  17. :rules="modalConfig.formRules"
  18. label-suffix=":"
  19. :model="formData"
  20. :label-width="modalConfig.labelWidth || '100px'"
  21. size="large"
  22. >
  23. <el-row :gutter="12">
  24. <template v-for="item in modalConfig.formItems" :key="item.prop">
  25. <el-col :span="item.span || 8">
  26. <el-form-item :label="item.label" :prop="item.prop">
  27. <template v-if="item.type === 'input'">
  28. <el-input
  29. :disabled="item.disabled"
  30. v-model="formData[item.prop]"
  31. :placeholder="item.placeholder"
  32. />
  33. </template>
  34. <template v-if="item.type === 'number'">
  35. <el-input
  36. v-model="formData[item.prop]"
  37. type="number"
  38. :min="0"
  39. :max="999999999999"
  40. :disabled="item.disabled"
  41. :placeholder="item.placeholder"
  42. />
  43. </template>
  44. <template v-if="item.type === 'select'">
  45. <el-select
  46. v-model="formData[item.prop]"
  47. :placeholder="item.placeholder"
  48. style="width: 100%"
  49. :disabled="item.disabled"
  50. >
  51. <template v-for="(val, index) in item.options" :key="index">
  52. <el-option :value="val.value" :label="val.label" />
  53. </template>
  54. </el-select>
  55. </template>
  56. <template v-if="item.type === 'date-picker'">
  57. <el-date-picker
  58. :type="item.dateType || 'daterange'"
  59. range-separator="-"
  60. start-placeholder="开始时间"
  61. end-placeholder="结束时间"
  62. v-model="formData[item.prop]"
  63. :disabled="item.disabled"
  64. />
  65. </template>
  66. <template v-if="item.type === 'date'">
  67. <el-date-picker
  68. type="date"
  69. :placeholder="item.placeholder"
  70. style="width: 100%"
  71. v-model="formData[item.prop]"
  72. :disabled="item.disabled"
  73. />
  74. </template>
  75. <template v-if="item.type === 'msgRecipient'">
  76. <el-radio-group v-model="formData[item.prop]">
  77. <el-radio v-for="vax in bj_msg_recipient" border :label="vax.value">{{
  78. vax.label
  79. }}</el-radio>
  80. </el-radio-group>
  81. </template>
  82. <template v-if="item.type === 'contactName'">
  83. <el-select
  84. :disabled="item.disabled"
  85. v-model="formData[item.prop]"
  86. filterable
  87. remote
  88. reserve-keyword
  89. :placeholder="item.placeholder"
  90. :remote-method="remoteuserNameMethod"
  91. :loading="userLoading"
  92. remote-show-suffix
  93. style="width: 100%"
  94. >
  95. <el-option
  96. v-for="item in userNameOptions"
  97. :key="item.value"
  98. :label="item.label"
  99. :value="item.value"
  100. />
  101. </el-select>
  102. </template>
  103. <template v-if="item.type === 'unitName'">
  104. <el-tree-select
  105. v-model="formData[item.prop]"
  106. :data="unitOptions"
  107. node-key="id"
  108. filterable
  109. check-strictly="true"
  110. :placeholder="item.placeholder"
  111. style="width: 100%"
  112. />
  113. </template>
  114. <template v-if="item.type === 'belongsDept'">
  115. <el-tree-select
  116. v-model="formData[item.prop]"
  117. :data="belongsDeptOptions"
  118. :render-after-expand="false"
  119. node-key="id"
  120. filterable
  121. :placeholder="item.placeholder"
  122. style="width: 100%"
  123. />
  124. </template>
  125. <template v-if="item.type === 'abStatus'">
  126. <el-radio-group v-model="formData[item.prop]">
  127. <el-radio v-for="vax in bj_ab_status" border :label="vax.value">{{
  128. vax.label
  129. }}</el-radio>
  130. </el-radio-group>
  131. </template>
  132. </el-form-item>
  133. </el-col>
  134. </template>
  135. </el-row>
  136. </el-form>
  137. </div>
  138. <template #footer>
  139. <span class="dialog-footer">
  140. <el-button @click="handleExcel(ruleFormRef)">返回</el-button>
  141. <el-button type="primary" v-show="dialogLook == false" @click="handleConfirmClick(ruleFormRef)"
  142. >确定</el-button
  143. >
  144. <slot name="button"></slot>
  145. </span>
  146. <el-col span="24">
  147. <img class="imgClass" src="@/assets/person-add.png" />
  148. </el-col>
  149. </template>
  150. </el-dialog>
  151. </div>
  152. </template>
  153. <script setup lang="ts" name="modal">
  154. import { reactive, ref } from 'vue';
  155. import type { FormInstance } from 'element-plus';
  156. import useSystemStore from '@/store/main';
  157. import { getDeptTree } from '@/api/address/index';
  158. import { outTypeList } from '@/libs/commonMeth';
  159. const bj_msg_recipient = outTypeList('bj_msg_recipient'); //短信接收人
  160. const bj_ab_status = outTypeList('bj_ab_status'); //短信接收人
  161. import dayjs from 'dayjs';
  162. // 定义props
  163. interface IProps {
  164. modalConfig: {
  165. pageName: string;
  166. addTitle: string;
  167. editTitle: string;
  168. detailTitle: string;
  169. dialogWidth: string;
  170. labelWidth: string;
  171. formItems: any[];
  172. formRules: object;
  173. pageListParams?: object; //新增一个对象,用来传给特殊的列表接口刷新页面(非必传)
  174. };
  175. otherInfo?: any;
  176. }
  177. const props = defineProps<IProps>();
  178. const dialogVisible = ref(false);
  179. const isEdit = ref(false);
  180. const ruleFormRef = ref<FormInstance>();
  181. const systemStore = useSystemStore();
  182. const { pageDetailInfo, pageOperateType } = storeToRefs(systemStore);
  183. interface userNameListItem {
  184. value: string;
  185. label: string;
  186. }
  187. const allOptions = ref<userNameListItem[]>([]);
  188. allOptions.value = [
  189. { label: '综合办公室-张三', value: 'Alabama' },
  190. { label: '科技信息处-李四', value: 'Alaska' },
  191. { label: '综合办公室-王五', value: 'Arizona' },
  192. { label: '科技信息处-赵六', value: 'California' },
  193. ];
  194. const userLoading = ref(false);
  195. const userNameOptions = ref<userNameListItem[]>([]);
  196. const remoteuserNameMethod = (query: string) => {
  197. if (query) {
  198. userLoading.value = true;
  199. setTimeout(() => {
  200. userLoading.value = false;
  201. userNameOptions.value = allOptions.value.filter(item => {
  202. return item.label.toLowerCase().includes(query.toLowerCase());
  203. });
  204. }, 200);
  205. } else {
  206. userNameOptions.value = allOptions.value;
  207. }
  208. };
  209. // const hideitem = (str: string) => {
  210. // if (isEdit.value == true) {
  211. // return true;
  212. // }
  213. // if (['addName', 'addDept', 'addDate'].includes(str)) {
  214. // return false;
  215. // } else {
  216. // return true;
  217. // }
  218. // };
  219. onMounted(async () => {
  220. getTree();
  221. });
  222. interface Tree {
  223. id: number;
  224. label: string;
  225. children?: Tree[];
  226. }
  227. const unitOptions: any = ref<Tree[]>();
  228. const belongsDeptOptions: any = ref<Tree[]>();
  229. // 过滤节点(搜索功能)
  230. const getTree = () => {
  231. getDeptTree().then((res: any) => {
  232. if (res.code == 200) {
  233. unitOptions.value = res.data;
  234. } else {
  235. unitOptions.value = [];
  236. }
  237. });
  238. };
  239. // 定义数据绑定
  240. const initialForm: any = {};
  241. for (const item of props.modalConfig.formItems) {
  242. initialForm[item.prop] = item.initialValue ?? '';
  243. }
  244. let formData = ref(JSON.parse(JSON.stringify(initialForm)));
  245. const dialogTitle = ref();
  246. const dialogLook = ref(false);
  247. const nowStr = dayjs().format('YYYY-MM-DD HH:mm:ss');
  248. // 新建或者编辑
  249. async function setDialogVisible(isNew: boolean = true, check: boolean = false) {
  250. dialogVisible.value = true;
  251. ruleFormRef.value?.resetFields();
  252. await nextTick();
  253. dialogLook.value = false;
  254. if (!isNew) {
  255. watch(pageDetailInfo, newVal => {
  256. formData.value = pageDetailInfo.value;
  257. });
  258. if (check) {
  259. dialogTitle.value = props.modalConfig.detailTitle;
  260. dialogLook.value = true;
  261. systemStore.getDetailType('detail');
  262. } else {
  263. dialogTitle.value = props.modalConfig.editTitle;
  264. systemStore.getDetailType('edit');
  265. }
  266. } else {
  267. props.modalConfig.formItems.map((m: any) => {
  268. if (m.prop === 'msgRecipient') {
  269. initialForm[m.prop] = '1';
  270. }
  271. if (m.prop === 'abStatus') {
  272. initialForm[m.prop] = '1';
  273. }
  274. if (m.prop === 'addName') {
  275. initialForm[m.prop] = '张浩楠';
  276. }
  277. if (m.prop === 'addDept') {
  278. initialForm[m.prop] = '交通运输部海事局';
  279. }
  280. if (m.prop === 'addDate') {
  281. initialForm[m.prop] = nowStr;
  282. }
  283. });
  284. formData.value = JSON.parse(JSON.stringify(initialForm));
  285. await nextTick();
  286. dialogTitle.value = props.modalConfig.addTitle;
  287. systemStore.detailPageEval(initialForm);
  288. systemStore.getDetailType('add');
  289. }
  290. isEdit.value = !isNew;
  291. }
  292. watch(
  293. () => formData.value.unitName,
  294. (newVal, oldVal) => {
  295. belongsDeptOptions.value = getChildrenById(unitOptions.value, newVal);
  296. }
  297. );
  298. /** 深度优先搜索,找到第一个 id 匹配的节点并返回它的 children */
  299. function getChildrenById(treeData: any[], targetId: string): any {
  300. for (const node of treeData) {
  301. if (node.id === targetId) {
  302. return node.children;
  303. }
  304. if (node.children) {
  305. const found = getChildrenById(node.children, targetId);
  306. if (found) return found;
  307. }
  308. }
  309. return [];
  310. }
  311. // 点击确定
  312. function handleConfirmClick(formEl: FormInstance | undefined) {
  313. if (!formEl) return;
  314. formEl.validate((valid, fields) => {
  315. if (valid) {
  316. dialogVisible.value = false;
  317. let data = { ...formData.value };
  318. if (props.otherInfo) {
  319. data = { ...data, ...props.otherInfo };
  320. }
  321. if (!isEdit.value) {
  322. systemStore.newPageDataAction(props.modalConfig.pageName, data, props.modalConfig.pageListParams);
  323. } else {
  324. if (pageOperateType.value === 'edit') {
  325. systemStore.editPageDataAction(props.modalConfig.pageName, data, props.modalConfig.pageListParams);
  326. }
  327. }
  328. } else {
  329. console.log('error submit!', fields);
  330. }
  331. });
  332. }
  333. // 取消
  334. function handleExcel(formEl: FormInstance | undefined) {
  335. dialogVisible.value = false;
  336. if (!formEl) return;
  337. formEl.resetFields();
  338. }
  339. // 获取详情
  340. function onPageDetail(urlId: number | [] | string) {
  341. systemStore.detailPageDataAction(props.modalConfig.pageName, urlId);
  342. }
  343. defineExpose({
  344. setDialogVisible,
  345. onPageDetail,
  346. });
  347. </script>
  348. <style scoped lang="scss">
  349. .form {
  350. padding: 10px 30px;
  351. }
  352. .imgClass {
  353. margin-top: 5%;
  354. width: 100%;
  355. }
  356. </style>