index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. <template>
  2. <div class="tenant">
  3. <!-- <Banner /> -->
  4. <div class="content">
  5. <byTable
  6. :source="sourceList.data"
  7. :pagination="sourceList.pagination"
  8. :config="config"
  9. :loading="loading"
  10. highlight-current-row
  11. :selectConfig="selectConfig"
  12. :table-events="{
  13. //element talbe事件都能传
  14. select: select,
  15. }"
  16. :action-list="[
  17. {
  18. text: '添加联系人',
  19. action: () => openModal('add'),
  20. },
  21. ]"
  22. @get-list="getList"
  23. >
  24. <template #phoneNumber="{ item }">
  25. <div>
  26. <span v-for="(x, index) in getTypeData(item, 0)">
  27. {{ x.contactNumber }}
  28. <span v-if="index < getTypeData(item, 0).length - 1">,</span>
  29. </span>
  30. </div>
  31. </template>
  32. <template #email="{ item }">
  33. <div>
  34. <span v-for="(x, index) in getTypeData(item, 1)">
  35. {{ x.contactNumber }}
  36. <span v-if="index < getTypeData(item, 1).length - 1">,</span>
  37. </span>
  38. </div>
  39. </template>
  40. </byTable>
  41. </div>
  42. <el-dialog
  43. :title="modalType == 'add' ? '添加联系人' : '编辑联系人'"
  44. v-model="dialogVisible"
  45. width="800"
  46. v-loading="loading"
  47. >
  48. <byForm
  49. :formConfig="formConfig"
  50. :formOption="formOption"
  51. v-model="formData.data"
  52. :rules="rules"
  53. ref="byform"
  54. >
  55. <template #enterpriseSlot>
  56. <div style="width: 100%">
  57. <el-select
  58. filterable
  59. allow-create
  60. v-model="formData.data.enterpriseId"
  61. :disabled="modalType !== 'add'"
  62. >
  63. <el-option
  64. v-for="item in enterpriseData"
  65. :label="item.enterpriseName"
  66. :value="item.enterpriseId"
  67. >
  68. </el-option>
  69. </el-select>
  70. </div>
  71. </template>
  72. <template #fileSlot>
  73. <div style="width: 100%">
  74. <el-button type="primary" @click="addRow"> 添加 </el-button>
  75. <el-form
  76. ref="tableForm"
  77. :model="formData.data"
  78. :rules="rules"
  79. label-width="0px"
  80. style="margin-top: 15px"
  81. >
  82. <el-table
  83. :data="formData.data.contactsList"
  84. v-if="modalType == 'add'"
  85. >
  86. <el-table-column
  87. prop="contactName"
  88. label="联系人"
  89. min-width="150"
  90. >
  91. <template #default="{ row, $index }">
  92. <el-form-item
  93. :prop="'contactsList.' + $index + '.contactName'"
  94. :rules="rules.contactName"
  95. :inline-message="true"
  96. >
  97. <el-input
  98. v-model="row.contactName"
  99. placeholder="请输入"
  100. />
  101. </el-form-item>
  102. </template>
  103. </el-table-column>
  104. <el-table-column
  105. prop="phoneNumber"
  106. label="手机号"
  107. min-width="150"
  108. >
  109. <template #default="{ row, $index }">
  110. <el-form-item
  111. :prop="'contactsList.' + $index + '.phoneNumber'"
  112. :rules="rules.phoneNumber"
  113. :inline-message="true"
  114. >
  115. <el-input
  116. v-model="row.phoneNumber"
  117. placeholder="请输入"
  118. />
  119. </el-form-item>
  120. </template>
  121. </el-table-column>
  122. <el-table-column prop="zip" label="操作" width="100">
  123. <template #default="{ $index }">
  124. <el-button type="primary" link @click="handleRemove($index)"
  125. >删除</el-button
  126. >
  127. </template>
  128. </el-table-column>
  129. </el-table>
  130. <el-table
  131. :data="formData.data.externalAddressBookList"
  132. v-if="modalType == 'edit'"
  133. >
  134. <el-table-column prop="type" label="类型" min-width="150">
  135. <template #default="{ row, $index }">
  136. <el-form-item
  137. :prop="'internalAddressBookList.' + $index + '.type'"
  138. :inline-message="true"
  139. >
  140. <!-- :rules="rules.type" -->
  141. <el-select v-model="row.type" placeholder="请选择">
  142. <el-option
  143. v-for="item in contactInformationType"
  144. :label="item.dictValue"
  145. :value="item.dictKey"
  146. >
  147. </el-option>
  148. </el-select>
  149. </el-form-item>
  150. </template>
  151. </el-table-column>
  152. <el-table-column
  153. prop="contactNumber"
  154. label="联系号码"
  155. min-width="150"
  156. >
  157. <template #default="{ row, $index }">
  158. <el-form-item
  159. :prop="
  160. 'internalAddressBookList.' + $index + '.contactNumber'
  161. "
  162. :inline-message="true"
  163. >
  164. <!-- :rules="rules.contactNumber" -->
  165. <el-input
  166. v-model="row.contactNumber"
  167. placeholder="请输入"
  168. />
  169. </el-form-item>
  170. </template>
  171. </el-table-column>
  172. <el-table-column prop="zip" label="操作" width="100">
  173. <template #default="{ $index }">
  174. <el-button type="primary" link @click="handleRemove($index)"
  175. >删除</el-button
  176. >
  177. </template>
  178. </el-table-column>
  179. </el-table>
  180. </el-form>
  181. </div>
  182. </template>
  183. </byForm>
  184. <template #footer>
  185. <el-button @click="dialogVisible = false" size="large">取 消</el-button>
  186. <el-button
  187. type="primary"
  188. @click="submitForm('byform')"
  189. size="large"
  190. :loading="submitLoading"
  191. >
  192. 确 定
  193. </el-button>
  194. </template>
  195. </el-dialog>
  196. </div>
  197. </template>
  198. <script setup>
  199. /* eslint-disable vue/no-unused-components */
  200. import { ElMessage, ElMessageBox } from "element-plus";
  201. import byTable from "@/components/byTable/index";
  202. import byForm from "@/components/byForm/index";
  203. import FileUpload from "@/components/FileUpload/index";
  204. import { computed, defineComponent, ref } from "vue";
  205. import { getToken } from "@/utils/auth";
  206. import useUserStore from "@/store/modules/user";
  207. const uploadFileUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); // 上传文件服务器地址
  208. const headers = ref({ Authorization: "Bearer " + getToken() });
  209. const uploadData = ref({});
  210. const loading = ref(false);
  211. const submitLoading = ref(false);
  212. const sourceList = ref({
  213. data: [],
  214. pagination: {
  215. total: 3,
  216. pageNum: 1,
  217. pageSize: 10,
  218. keyword: "",
  219. },
  220. });
  221. let dialogVisible = ref(false);
  222. let modalType = ref("add");
  223. let fileList = ref([]);
  224. let rules = ref({
  225. enterpriseId: [
  226. { required: true, message: "请选择/输入企业", trigger: ["change", "blur"] },
  227. ],
  228. contactName: [{ required: true, message: "请输入联系人", trigger: "blur" }],
  229. phoneNumber: [{ required: true, message: "请输入联系电话", trigger: "blur" }],
  230. type: [{ required: true, message: "请选择联系类型", trigger: "change" }],
  231. contactNumber: [
  232. { required: true, message: "请输入联系号码", trigger: "blur" },
  233. ],
  234. });
  235. const { proxy } = getCurrentInstance();
  236. const selectConfig = reactive([
  237. {
  238. label: "来源",
  239. prop: "enterpriseType",
  240. data: [
  241. {
  242. label: "客户",
  243. value: "1",
  244. },
  245. {
  246. label: "供应商",
  247. value: "2",
  248. },
  249. {
  250. label: "自定义",
  251. value: "3",
  252. },
  253. ],
  254. },
  255. ]);
  256. const config = computed(() => {
  257. return [
  258. {
  259. attrs: {
  260. label: "来源",
  261. prop: "enterpriseType",
  262. },
  263. render(enterpriseType) {
  264. return enterpriseType === 1
  265. ? "客户"
  266. : enterpriseType === 2
  267. ? "供应商"
  268. : enterpriseType === 3
  269. ? "自定义"
  270. : "";
  271. },
  272. },
  273. {
  274. attrs: {
  275. label: "关联企业",
  276. prop: "enterpriseName",
  277. },
  278. },
  279. {
  280. attrs: {
  281. label: "联系人",
  282. prop: "contactName",
  283. },
  284. },
  285. {
  286. attrs: {
  287. type: "slot",
  288. slot: "phoneNumber",
  289. label: "手机号",
  290. },
  291. },
  292. {
  293. attrs: {
  294. type: "slot",
  295. slot: "email",
  296. label: "电子邮箱",
  297. },
  298. },
  299. // {
  300. // attrs: {
  301. // label: "座机",
  302. // prop: "createTime",
  303. // },
  304. // },
  305. // {
  306. // attrs: {
  307. // label: "WhatsApp",
  308. // prop: "createTime",
  309. // },
  310. // },
  311. {
  312. attrs: {
  313. label: "操作",
  314. width: "200",
  315. align: "right",
  316. },
  317. // 渲染 el-button,一般用在最后一列。
  318. renderHTML(row) {
  319. return [
  320. {
  321. attrs: {
  322. label: "修改",
  323. type: "primary",
  324. text: true,
  325. },
  326. el: "button",
  327. click() {
  328. getDtl(row);
  329. },
  330. },
  331. {
  332. attrs: {
  333. label: "删除",
  334. type: "danger",
  335. text: true,
  336. },
  337. el: "button",
  338. click() {
  339. // 弹窗提示是否删除
  340. ElMessageBox.confirm(
  341. "此操作将永久删除该数据, 是否继续?",
  342. "提示",
  343. {
  344. confirmButtonText: "确定",
  345. cancelButtonText: "取消",
  346. type: "warning",
  347. }
  348. ).then(() => {
  349. // 删除
  350. proxy
  351. .post("/contacts/delete", {
  352. id: row.id,
  353. })
  354. .then((res) => {
  355. ElMessage({
  356. message: "删除成功",
  357. type: "success",
  358. });
  359. getList();
  360. });
  361. });
  362. },
  363. },
  364. ];
  365. },
  366. },
  367. ];
  368. });
  369. let formData = reactive({
  370. data: {
  371. type: "1",
  372. },
  373. });
  374. const formOption = reactive({
  375. inline: true,
  376. labelWidth: 100,
  377. itemWidth: 100,
  378. rules: [],
  379. });
  380. const byform = ref(null);
  381. const formConfig = ref([]);
  382. const getList = async (req) => {
  383. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  384. loading.value = true;
  385. proxy.post("/contacts/page", sourceList.value.pagination).then((message) => {
  386. console.log(message);
  387. sourceList.value.data = message.rows;
  388. sourceList.value.pagination.total = message.total;
  389. setTimeout(() => {
  390. loading.value = false;
  391. }, 200);
  392. });
  393. };
  394. const openModal = () => {
  395. dialogVisible.value = true;
  396. formConfig.value = configData[0];
  397. modalType.value = "add";
  398. formData.data = {
  399. contactsList: [],
  400. };
  401. };
  402. const submitForm = () => {
  403. byform.value.handleSubmit((valid) => {
  404. if (modalType.value === "add") {
  405. if (formData.data.contactsList.length > 0) {
  406. proxy.$refs.tableForm.validate((vaild) => {
  407. if (vaild) {
  408. const current = enterpriseData.value.find(
  409. (x) => x.enterpriseId === formData.data.enterpriseId
  410. );
  411. if (current && current !== undefined) {
  412. formData.data.enterpriseType = current.enterpriseType;
  413. } else {
  414. formData.data.enterpriseType = 3;
  415. formData.data.enterpriseName = formData.data.enterpriseId;
  416. formData.data.enterpriseId = "";
  417. }
  418. submitLoading.value = true;
  419. proxy.post("/contacts/" + modalType.value, formData.data).then(
  420. (res) => {
  421. ElMessage({
  422. message: modalType.value == "add" ? "添加成功" : "编辑成功",
  423. type: "success",
  424. });
  425. dialogVisible.value = false;
  426. submitLoading.value = false;
  427. getList();
  428. },
  429. (err) => {
  430. submitLoading.value = false;
  431. }
  432. );
  433. }
  434. });
  435. } else {
  436. return ElMessage({
  437. message: "请添加联系人!",
  438. type: "info",
  439. });
  440. }
  441. } else {
  442. if (formData.data.externalAddressBookList.length > 0) {
  443. proxy.$refs.tableForm.validate((vaild) => {
  444. if (vaild) {
  445. submitLoading.value = true;
  446. proxy.post("/contacts/" + modalType.value, formData.data).then(
  447. (res) => {
  448. const submitData = {
  449. contactsId: formData.data.id,
  450. externalAddressBookList:
  451. formData.data.externalAddressBookList.map((x) => ({
  452. ...x,
  453. })),
  454. };
  455. proxy
  456. .post("/externalAddressBook/" + modalType.value, submitData)
  457. .then((res) => {
  458. ElMessage({
  459. message: "编辑成功",
  460. type: "success",
  461. });
  462. dialogVisible.value = false;
  463. submitLoading.value = false;
  464. getList();
  465. });
  466. },
  467. (err) => {
  468. submitLoading.value = false;
  469. }
  470. );
  471. }
  472. });
  473. } else {
  474. return ElMessage({
  475. message: "请添加联系方式!",
  476. type: "info",
  477. });
  478. }
  479. }
  480. });
  481. };
  482. const configData = [
  483. [
  484. {
  485. type: "slot",
  486. slotName: "enterpriseSlot",
  487. prop: "enterpriseId",
  488. label: "关联企业",
  489. },
  490. {
  491. type: "slot",
  492. slotName: "fileSlot",
  493. label: "联系方式",
  494. },
  495. ],
  496. [
  497. {
  498. type: "slot",
  499. slotName: "enterpriseSlot",
  500. prop: "enterpriseId",
  501. label: "关联企业",
  502. },
  503. {
  504. prop: "contactName",
  505. type: "input",
  506. label: "联系人",
  507. },
  508. {
  509. type: "slot",
  510. slotName: "fileSlot",
  511. label: "联系方式",
  512. },
  513. ],
  514. ];
  515. const enterpriseData = ref([]);
  516. const contactInformationType = ref([]);
  517. const getDict = () => {
  518. const tenantId = useUserStore().user.tenantId;
  519. proxy
  520. .post("/dictTenantData/page", {
  521. pageNum: 1,
  522. pageSize: 999,
  523. tenantId: tenantId,
  524. dictCode: "contact_information",
  525. })
  526. .then((res) => {
  527. contactInformationType.value = res.rows;
  528. });
  529. proxy.post("/contacts/list", { pageNum: 1, pageSize: 9999 }).then((res) => {
  530. enterpriseData.value = res;
  531. });
  532. };
  533. const getDtl = (row) => {
  534. modalType.value = "edit";
  535. formConfig.value = configData[1];
  536. dialogVisible.value = true;
  537. proxy.post("/contacts/detail", { id: row.id }).then((res) => {
  538. formData.data = res;
  539. proxy.post("/externalAddressBook/detail", { id: row.id }).then((res) => {
  540. formData.data.externalAddressBookList =
  541. res.map((x) => ({
  542. id: x.id,
  543. type: x.type + "",
  544. contactNumber: x.contactNumber,
  545. })) || [];
  546. });
  547. });
  548. };
  549. const handleRemove = (index) => {
  550. if (modalType.value === "add") {
  551. formData.data.contactsList.splice(index, 1);
  552. } else {
  553. formData.data.externalAddressBookList.splice(index, 1);
  554. }
  555. };
  556. getList();
  557. getDict();
  558. const addRow = () => {
  559. if (modalType.value === "add") {
  560. formData.data.contactsList.push({
  561. contactName: "",
  562. phoneNumber: "",
  563. });
  564. } else {
  565. formData.data.externalAddressBookList.push({
  566. id: "",
  567. type: "",
  568. contactNumber: "",
  569. });
  570. }
  571. };
  572. const getTypeData = (item, type) => {
  573. if (item.internalAddressBookList)
  574. return item.internalAddressBookList.filter((x) => x.type === type) || [];
  575. };
  576. </script>
  577. <style lang="scss" scoped>
  578. .tenant {
  579. padding: 20px;
  580. }
  581. </style>