index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. <template>
  2. <div class="tenant">
  3. <div class="content">
  4. <byTable
  5. :source="sourceList.data"
  6. :pagination="sourceList.pagination"
  7. :config="config"
  8. :loading="loading"
  9. :selectConfig="selectConfig"
  10. highlight-current-row
  11. :action-list="[
  12. {
  13. text: '添加用户',
  14. action: () => openModal('add'),
  15. },
  16. ]"
  17. @get-list="getList">
  18. <template #fileSlot="{ item }">
  19. <span>{{ item.countryName }}</span>
  20. <span v-if="item.provinceName"> ,{{ item.provinceName }}</span>
  21. <span v-if="item.cityName"> ,{{ item.cityName }}</span>
  22. </template>
  23. </byTable>
  24. </div>
  25. <el-dialog :title="modalType == 'add' ? '新增' : '编辑'" v-model="dialogVisible" width="800" v-loading="loadingOperation">
  26. <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="submit">
  27. <template #address>
  28. <el-row :gutter="10" style="width: 100%; margin-left: -15px">
  29. <el-col :span="8">
  30. <el-form-item prop="countryId">
  31. <el-select v-model="formData.data.countryId" placeholder="国家" @change="(val) => getCityData(val, '20', true)">
  32. <el-option v-for="item in countryData" :label="item.chineseName" :value="item.id"> </el-option>
  33. </el-select>
  34. </el-form-item>
  35. </el-col>
  36. <el-col :span="8">
  37. <el-form-item prop="provinceId">
  38. <el-select v-model="formData.data.provinceId" placeholder="省/洲" @change="(val) => getCityData(val, '30', true)">
  39. <el-option v-for="item in provinceData" :label="item.name" :value="item.id"> </el-option>
  40. </el-select>
  41. </el-form-item>
  42. </el-col>
  43. <el-col :span="8">
  44. <el-form-item prop="cityId">
  45. <el-select v-model="formData.data.cityId" placeholder="城市">
  46. <el-option v-for="item in cityData" :label="item.name" :value="item.id"> </el-option>
  47. </el-select>
  48. </el-form-item>
  49. </el-col>
  50. </el-row>
  51. <el-row style="margin-top: 20px; width: 100%; margin-left: -10px">
  52. <el-col :span="24">
  53. <el-form-item prop="address">
  54. <el-input v-model="formData.data.address" type="textarea"> </el-input>
  55. </el-form-item>
  56. </el-col>
  57. </el-row>
  58. </template>
  59. <template #person>
  60. <div>
  61. <el-button type="primary" @click="clickAddPerson"> 添加 </el-button>
  62. <byTable :source="formData.data.customerUserList" :config="configPerson" hideSearch hidePagination> </byTable>
  63. </div>
  64. </template>
  65. </byForm>
  66. <template #footer>
  67. <el-button @click="dialogVisible = false" size="large">取 消</el-button>
  68. <el-button type="primary" @click="submitForm('submit')" size="large" :loading="submitLoading"> 确 定 </el-button>
  69. </template>
  70. </el-dialog>
  71. <el-dialog title="添加联系人" v-model="openPerson" width="400" v-loading="openPerson">
  72. <byForm :formConfig="formConfigPerson" :formOption="formOption" v-model="formPerson.data" :rules="rulesPerson" ref="person"> </byForm>
  73. <template #footer>
  74. <el-button @click="openPerson = false" size="large">取 消</el-button>
  75. <el-button type="primary" @click="submitPerson('person')" size="large"> 确 定 </el-button>
  76. </template>
  77. </el-dialog>
  78. </div>
  79. </template>
  80. <script setup>
  81. import { ElMessage, ElMessageBox } from "element-plus";
  82. import byTable from "@/components/byTable/index";
  83. import byForm from "@/components/byForm/index";
  84. import { computed, ref } from "vue";
  85. import useUserStore from "@/store/modules/user";
  86. const { proxy } = getCurrentInstance();
  87. const loading = ref(false);
  88. const loadingOperation = ref(false);
  89. const submitLoading = ref(false);
  90. const openPerson = ref(false);
  91. const customerSource = ref([]);
  92. const customerStatus = ref([]);
  93. const sourceList = ref({
  94. data: [],
  95. pagination: {
  96. total: 0,
  97. pageNum: 1,
  98. pageSize: 10,
  99. status: "",
  100. source: "",
  101. type: "0",
  102. },
  103. });
  104. const selectConfig = computed(() => {
  105. return [
  106. {
  107. label: "客户来源",
  108. prop: "source",
  109. data: customerSource.value,
  110. },
  111. {
  112. label: "客户类型",
  113. prop: "status",
  114. data: customerStatus.value,
  115. },
  116. ];
  117. });
  118. const config = computed(() => {
  119. return [
  120. {
  121. attrs: {
  122. label: "客户名称",
  123. prop: "name",
  124. },
  125. },
  126. {
  127. attrs: {
  128. label: "所在城市",
  129. slot: "address",
  130. width: 200,
  131. },
  132. },
  133. {
  134. attrs: {
  135. label: "客户代码",
  136. prop: "customerCode",
  137. width: 140,
  138. },
  139. },
  140. {
  141. attrs: {
  142. label: "客户来源",
  143. prop: "source",
  144. width: 140,
  145. },
  146. render(type) {
  147. let data = customerSource.value.filter((item) => item.value == type);
  148. if (data && data.length > 0) {
  149. return data[0].label;
  150. } else {
  151. return "";
  152. }
  153. },
  154. },
  155. {
  156. attrs: {
  157. label: "客户类型",
  158. prop: "status",
  159. width: 140,
  160. },
  161. render(type) {
  162. let data = customerStatus.value.filter((item) => item.value == type);
  163. if (data && data.length > 0) {
  164. return data[0].label;
  165. } else {
  166. return "";
  167. }
  168. },
  169. },
  170. {
  171. attrs: {
  172. label: "操作",
  173. width: "100",
  174. align: "center",
  175. },
  176. renderHTML(row) {
  177. return [
  178. {
  179. attrs: {
  180. label: "认领客户",
  181. type: "primary",
  182. text: true,
  183. },
  184. el: "button",
  185. click() {
  186. ElMessageBox.confirm("是否确定认领该客户?", "提示", {
  187. confirmButtonText: "确定",
  188. cancelButtonText: "取消",
  189. type: "warning",
  190. }).then(() => {
  191. proxy
  192. .post("/customer/CustomerAllocation", {
  193. id: row.id,
  194. userId: useUserStore().user.userId,
  195. })
  196. .then(() => {
  197. ElMessage({
  198. message: "认领成功",
  199. type: "success",
  200. });
  201. getList();
  202. });
  203. });
  204. },
  205. },
  206. ];
  207. },
  208. },
  209. ];
  210. });
  211. let modalType = ref("add");
  212. let dialogVisible = ref(false);
  213. let formData = reactive({
  214. data: {
  215. countryId: "China",
  216. },
  217. });
  218. let formPerson = reactive({
  219. data: {},
  220. });
  221. const formOption = reactive({
  222. inline: true,
  223. labelWidth: 100,
  224. itemWidth: 100,
  225. rules: [],
  226. });
  227. const formConfig = computed(() => {
  228. return [
  229. {
  230. type: "input",
  231. prop: "name",
  232. label: "客户名称",
  233. required: true,
  234. itemWidth: 100,
  235. itemType: "text",
  236. },
  237. {
  238. type: "slot",
  239. slotName: "address",
  240. label: "详细地址",
  241. },
  242. {
  243. type: "input",
  244. prop: "customerCode",
  245. label: "客户代码",
  246. required: true,
  247. itemWidth: 100,
  248. itemType: "text",
  249. },
  250. {
  251. type: "select",
  252. label: "客户来源",
  253. prop: "source",
  254. itemWidth: 50,
  255. isLoad: {
  256. url: "/dictTenantData/page",
  257. labelKey: "dictValue",
  258. labelVal: "dictKey",
  259. method: "post",
  260. req: {
  261. pageNum: 1,
  262. pageSize: 999,
  263. dictCode: "customer_source",
  264. tenantId: useUserStore().user.tenantId,
  265. },
  266. resUrl: "rows",
  267. },
  268. },
  269. {
  270. type: "select",
  271. label: "客户类型",
  272. prop: "status",
  273. itemWidth: 50,
  274. isLoad: {
  275. url: "/dictTenantData/page",
  276. labelKey: "dictValue",
  277. labelVal: "dictKey",
  278. method: "post",
  279. req: {
  280. pageNum: 1,
  281. pageSize: 999,
  282. dictCode: "customer_status",
  283. tenantId: useUserStore().user.tenantId,
  284. },
  285. resUrl: "rows",
  286. },
  287. },
  288. {
  289. type: "select",
  290. label: "业务员",
  291. prop: "userId",
  292. itemWidth: 100,
  293. isLoad: {
  294. url: "/tenantUser/list?pageNum=1&pageSize=10000",
  295. labelKey: "userName",
  296. labelVal: "userId",
  297. method: "get",
  298. resUrl: "rows",
  299. },
  300. },
  301. {
  302. type: "slot",
  303. slotName: "person",
  304. label: "客户联系人",
  305. },
  306. ];
  307. });
  308. let rules = ref({
  309. name: [{ required: true, message: "请输入客户名称", trigger: "blur" }],
  310. countryId: [{ required: true, message: "请选择国家", trigger: "change" }],
  311. provinceId: [{ required: true, message: "请选择省/州", trigger: "change" }],
  312. // cityId: [{ required: true, message: "请选择城市", trigger: "change" }],
  313. source: [{ required: true, message: "请选择客户来源", trigger: "change" }],
  314. status: [{ required: true, message: "请选择类型", trigger: "change" }],
  315. });
  316. const formConfigPerson = computed(() => {
  317. return [
  318. {
  319. type: "input",
  320. prop: "name",
  321. label: "联系人名称",
  322. required: true,
  323. itemWidth: 100,
  324. itemType: "text",
  325. },
  326. {
  327. type: "input",
  328. prop: "phone",
  329. label: "联系人电话",
  330. required: true,
  331. itemWidth: 100,
  332. itemType: "text",
  333. },
  334. ];
  335. });
  336. const configPerson = computed(() => {
  337. return [
  338. {
  339. attrs: {
  340. label: "联系人名称",
  341. prop: "name",
  342. width: 150,
  343. },
  344. },
  345. {
  346. attrs: {
  347. label: "联系人电话",
  348. prop: "phone",
  349. width: 440,
  350. },
  351. },
  352. {
  353. attrs: {
  354. label: "操作",
  355. width: "100",
  356. align: "center",
  357. },
  358. renderHTML(row) {
  359. return [
  360. {
  361. attrs: {
  362. label: "删除",
  363. type: "primary",
  364. text: true,
  365. },
  366. el: "button",
  367. click() {
  368. formData.data.customerUserList.splice(row.$index, 1);
  369. },
  370. },
  371. ];
  372. },
  373. },
  374. ];
  375. });
  376. let rulesPerson = ref({
  377. name: [{ required: true, message: "请输入联系人名称", trigger: "blur" }],
  378. phone: [{ required: true, message: "请输入联系人电话", trigger: "blur" }],
  379. });
  380. const submit = ref(null);
  381. const person = ref(null);
  382. const getList = async (req) => {
  383. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  384. loading.value = true;
  385. proxy.post("/customer/page", sourceList.value.pagination).then((res) => {
  386. sourceList.value.data = res.rows;
  387. sourceList.value.pagination.total = res.total;
  388. setTimeout(() => {
  389. loading.value = false;
  390. }, 200);
  391. });
  392. };
  393. const openModal = () => {
  394. modalType.value = "add";
  395. formData.data = {
  396. countryId: "China",
  397. };
  398. getCityData(formData.data.countryId, "20");
  399. loadingOperation.value = false;
  400. dialogVisible.value = true;
  401. };
  402. const countryData = ref([]);
  403. const provinceData = ref([]);
  404. const cityData = ref([]);
  405. const getCityData = (id, type, isChange) => {
  406. proxy.post("/areaInfo/list", { parentId: id }).then((res) => {
  407. if (type === "20") {
  408. provinceData.value = res;
  409. if (isChange) {
  410. formData.data.provinceId = "";
  411. formData.data.cityId = "";
  412. }
  413. } else if (type === "30") {
  414. cityData.value = res;
  415. if (isChange) {
  416. formData.data.cityId = "";
  417. }
  418. } else {
  419. countryData.value = res;
  420. }
  421. });
  422. };
  423. getCityData("0");
  424. const clickAddPerson = () => {
  425. formPerson.data = {};
  426. openPerson.value = true;
  427. };
  428. const submitPerson = () => {
  429. person.value.handleSubmit(() => {
  430. if (formData.data.customerUserList && formData.data.customerUserList.length > 0) {
  431. formData.data.customerUserList.push({
  432. name: formPerson.data.name,
  433. phone: formPerson.data.phone,
  434. });
  435. } else {
  436. formData.data.customerUserList = [
  437. {
  438. name: formPerson.data.name,
  439. phone: formPerson.data.phone,
  440. },
  441. ];
  442. }
  443. openPerson.value = false;
  444. });
  445. };
  446. const submitForm = () => {
  447. submit.value.handleSubmit(() => {
  448. if (formData.data.customerUserList && formData.data.customerUserList.length > 0) {
  449. submitLoading.value = true;
  450. proxy.post("/customer/" + modalType.value, formData.data).then(
  451. () => {
  452. ElMessage({
  453. message: modalType.value == "add" ? "添加成功" : "编辑成功",
  454. type: "success",
  455. });
  456. dialogVisible.value = false;
  457. submitLoading.value = false;
  458. getList();
  459. },
  460. (err) => {
  461. console.log(err);
  462. submitLoading.value = false;
  463. }
  464. );
  465. } else {
  466. ElMessage("请添加客户联系人");
  467. }
  468. });
  469. };
  470. const getDict = () => {
  471. proxy
  472. .post("/dictTenantData/page", {
  473. pageNum: 1,
  474. pageSize: 999,
  475. dictCode: "customer_source",
  476. tenantId: useUserStore().user.tenantId,
  477. })
  478. .then((res) => {
  479. customerSource.value = res.rows.map((item) => {
  480. return {
  481. label: item.dictValue,
  482. value: item.dictKey,
  483. };
  484. });
  485. });
  486. proxy
  487. .post("/dictTenantData/page", {
  488. pageNum: 1,
  489. pageSize: 999,
  490. dictCode: "customer_status",
  491. tenantId: useUserStore().user.tenantId,
  492. })
  493. .then((res) => {
  494. customerStatus.value = res.rows.map((item) => {
  495. return {
  496. label: item.dictValue,
  497. value: item.dictKey,
  498. };
  499. });
  500. });
  501. };
  502. getDict();
  503. getList();
  504. </script>
  505. <style lang="scss" scoped>
  506. .tenant {
  507. padding: 20px;
  508. }
  509. </style>