addCustomer.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. <template>
  2. <div>
  3. <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="submit" v-loading="loading">
  4. <template #name>
  5. <div style="width: 100%">
  6. <el-autocomplete v-model="formData.data.name" :fetch-suggestions="querySearch" clearable placeholder="请输入" style="width:100%" />
  7. </div>
  8. </template>
  9. <template #allAddress>
  10. <el-row style="width: 100%">
  11. <el-col :span="8">
  12. <el-form-item prop="countryId" class="wid100">
  13. <el-select v-model="formData.data.countryId" placeholder="国家" filterable style="width:100%"
  14. @change="(val) => getCityData(val, '20', true)">
  15. <el-option v-for="item in countryData" :label="item.name" :value="item.id">
  16. </el-option>
  17. </el-select>
  18. </el-form-item>
  19. </el-col>
  20. <el-col :span="8">
  21. <el-form-item prop="provinceName" class="wid100">
  22. <selectCity placeholder="省/洲" @change="(val) => getCityData(val, '30', true)" style="width:100%" addressId="provinceId"
  23. addressName="provinceName" v-model="formData.data" :data="provinceData">
  24. </selectCity>
  25. </el-form-item>
  26. </el-col>
  27. <el-col :span="8">
  28. <el-form-item prop="cityName" class="wid100">
  29. <selectCity placeholder="城市" addressId="cityId" addressName="cityName" style="width:100%" v-model="formData.data" :data="cityData">
  30. </selectCity>
  31. </el-form-item>
  32. </el-col>
  33. </el-row>
  34. <el-row style=" width: 100%">
  35. <el-col :span="24">
  36. <el-form-item prop="address" class="margin-b-0 wid100">
  37. <el-input v-model="formData.data.address" type="textarea" placeholder="详细地址">
  38. </el-input>
  39. </el-form-item>
  40. </el-col>
  41. </el-row>
  42. </template>
  43. <template #person>
  44. <div style="width: 100%">
  45. <el-button type="primary" @click="clickAddPerson">添 加</el-button>
  46. <el-table :data="formData.data.customerUserList" style="width: 100%; margin-top: 16px">
  47. <el-table-column label="联系人" width="160">
  48. <template #default="{ row, $index }">
  49. <div style="width: 100%">
  50. <el-form-item :prop="'customerUserList.' + $index + '.name'" class="margin-b-0 wid100" :rules="rules.name2" :inline-message="true">
  51. <el-input v-model="row.name" placeholder="请输入联系人" />
  52. </el-form-item>
  53. </div>
  54. </template>
  55. </el-table-column>
  56. <el-table-column label="电子邮箱">
  57. <template #default="{ row, $index }">
  58. <div style="width: 100%">
  59. <el-form-item :prop="'customerUserList.' + $index + '.email'" class="margin-b-0 wid100" :rules="rules.email" :inline-message="true">
  60. <el-input v-model="row.email" placeholder="请输入电子邮箱" />
  61. </el-form-item>
  62. </div>
  63. </template>
  64. </el-table-column>
  65. <el-table-column align="center" label="操作" width="120" fixed="right">
  66. <template #default="{ row, $index }">
  67. <el-button type="primary" link @click="clickInformationMore(row, $index)">更多</el-button>
  68. <el-button type="primary" link @click="clickDelete($index)">删除</el-button>
  69. </template>
  70. </el-table-column>
  71. </el-table>
  72. </div>
  73. </template>
  74. </byForm>
  75. <el-dialog title="更多联系方式" v-if="openPerson" v-model="openPerson" width="700">
  76. <el-form :label-position="'right'" :model="formPerson.data" :rules="rulesPerson" ref="person" label-width="100px">
  77. <el-form-item label="联系人" prop="name">
  78. <el-input v-model="formPerson.data.name" placeholder="请输入" />
  79. </el-form-item>
  80. <el-form-item label="电子邮箱" prop="email">
  81. <el-input v-model="formPerson.data.email" placeholder="请输入" />
  82. </el-form-item>
  83. <el-form-item label="更多联系方式">
  84. <div style="width: 100%">
  85. <el-button type="primary" @click="clickAddMoreInformation">添 加</el-button>
  86. <el-table :data="formPerson.data.contact" style="width: 100%; margin-top: 16px">
  87. <el-table-column label="类型" width="180">
  88. <template #default="{ row, $index }">
  89. <div style="width: 100%">
  90. <el-form-item :prop="'contact.' + $index + '.type'" class="margin-b-0 wid100" :rules="rulesPerson.type" :inline-message="true">
  91. <el-select v-model="row.type" placeholder="请选择类型" style="width: 100%">
  92. <el-option v-for="item in contactType" :key="item.value" :label="item.label" :value="item.value" />
  93. </el-select>
  94. </el-form-item>
  95. </div>
  96. </template>
  97. </el-table-column>
  98. <el-table-column label="联系号码">
  99. <template #default="{ row, $index }">
  100. <div style="width: 100%">
  101. <el-form-item :prop="'contact.' + $index + '.contactNo'" class="margin-b-0 wid100" :rules="rulesPerson.contactNo"
  102. :inline-message="true">
  103. <el-input v-model="row.contactNo" placeholder="请输入联系号码" />
  104. </el-form-item>
  105. </div>
  106. </template>
  107. </el-table-column>
  108. <el-table-column align="center" label="操作" width="120" fixed="right">
  109. <template #default="{ $index }">
  110. <el-button type="primary" link @click="clickInformationDelete($index)">删除</el-button>
  111. </template>
  112. </el-table-column>
  113. </el-table>
  114. </div>
  115. </el-form-item>
  116. </el-form>
  117. <template #footer>
  118. <el-button @click="openPerson = false" size="default">取 消</el-button>
  119. <el-button type="primary" @click="submitPerson()" size="default">确 定</el-button>
  120. </template>
  121. </el-dialog>
  122. </div>
  123. </template>
  124. <script setup>
  125. import { ElMessage, ElMessageBox } from "element-plus";
  126. import byForm from "@/components/byForm/index";
  127. import useUserStore from "@/store/modules/user";
  128. import selectCity from "@/components/selectCity/index.vue";
  129. const props = defineProps({
  130. modalType: String,
  131. customerId: String,
  132. customerMail: {
  133. type: String,
  134. default: "",
  135. },
  136. isPrivate: {
  137. type: Boolean,
  138. default: false,
  139. },
  140. isHighseas: {
  141. type: Boolean,
  142. default: false,
  143. },
  144. });
  145. const modalType = ref("add");
  146. const isHighseas = ref(false);
  147. isHighseas.value = props.isHighseas;
  148. const customerId = ref("");
  149. const { proxy } = getCurrentInstance();
  150. const loading = ref(false);
  151. const customerTag = ref([]);
  152. const customerSource = ref([]);
  153. const customerStatus = ref([]);
  154. const contactType = ref([]);
  155. const userList = ref([]);
  156. const submit = ref(null);
  157. const formData = reactive({
  158. data: {
  159. countryId: "44",
  160. },
  161. });
  162. const getDict = () => {
  163. proxy
  164. .getDictOne([
  165. "customer_tag",
  166. "customer_source",
  167. "customer_status",
  168. "contact_type",
  169. ])
  170. .then((res) => {
  171. customerTag.value = res["customer_tag"].map((x) => ({
  172. label: x.dictValue,
  173. value: x.dictKey,
  174. }));
  175. customerSource.value = res["customer_source"].map((x) => ({
  176. label: x.dictValue,
  177. value: x.dictKey,
  178. }));
  179. console.log(res, "ss");
  180. customerStatus.value = res["customer_status"].map((x) => ({
  181. label: x.dictValue,
  182. value: x.dictKey,
  183. }));
  184. contactType.value = res["contact_type"].map((x) => ({
  185. label: x.dictValue,
  186. value: x.dictKey,
  187. }));
  188. });
  189. proxy
  190. .get("/tenantUser/list", {
  191. pageNum: 1,
  192. pageSize: 10000,
  193. tenantId: useUserStore().user.tenantId,
  194. })
  195. .then((res) => {
  196. userList.value = res.rows.map((item) => {
  197. return {
  198. label: item.nickName,
  199. value: item.userId,
  200. };
  201. });
  202. });
  203. };
  204. getDict();
  205. const countryData = ref([]);
  206. const provinceData = ref([]);
  207. const cityData = ref([]);
  208. const getCityData = (id, type, isChange = false) => {
  209. proxy.post("/customizeArea/list", { parentId: id }).then((res) => {
  210. if (type === "20") {
  211. provinceData.value = res;
  212. if (isChange) {
  213. formData.data.provinceId = "";
  214. formData.data.provinceName = "";
  215. formData.data.cityId = "";
  216. formData.data.cityName = "";
  217. }
  218. } else if (type === "30") {
  219. cityData.value = res;
  220. if (isChange) {
  221. formData.data.cityId = "";
  222. formData.data.cityName = "";
  223. }
  224. } else {
  225. countryData.value = res;
  226. }
  227. });
  228. };
  229. getCityData("0");
  230. const getDtl = () => {
  231. loading.value = true;
  232. proxy.post("/customer/detail", { id: customerId.value }).then((res) => {
  233. if (res.tag) {
  234. res.tags = res.tag.split(",");
  235. } else {
  236. res.tags = [];
  237. }
  238. formData.data = res;
  239. getCityData(formData.data.countryId, "20");
  240. if (formData.data.provinceId) {
  241. getCityData(formData.data.provinceId, "30");
  242. }
  243. loading.value = false;
  244. });
  245. };
  246. if (props && props.modalType) {
  247. modalType.value = props.modalType;
  248. if (modalType.value == "add") {
  249. formData.data = {
  250. countryId: "44",
  251. tags: [],
  252. customerUserList: [
  253. {
  254. name: "",
  255. email: "",
  256. },
  257. ],
  258. };
  259. if (props.customerMail) {
  260. formData.data.customerUserList[0].email = props.customerMail;
  261. }
  262. getCityData(formData.data.countryId, "20");
  263. } else if (modalType.value == "edit" && props.customerId) {
  264. customerId.value = props.customerId;
  265. getDtl();
  266. }
  267. }
  268. const formOption = reactive({
  269. inline: true,
  270. labelWidth: 190,
  271. itemWidth: 100,
  272. rules: [],
  273. });
  274. const formConfig = computed(() => {
  275. return [
  276. // {
  277. // type: "input",
  278. // prop: "name",
  279. // label: "客户名称",
  280. // required: true,
  281. // itemWidth: 100,
  282. // itemType: "text",
  283. // },
  284. {
  285. type: "title1",
  286. title: "基本信息",
  287. },
  288. {
  289. type: "slot",
  290. slotName: "name",
  291. prop: "name",
  292. label: "客户名称",
  293. },
  294. {
  295. type: "slot",
  296. slotName: "allAddress",
  297. label: "详细地址",
  298. },
  299. {
  300. type: "select",
  301. label: "客户来源",
  302. prop: "source",
  303. itemWidth: 50,
  304. data: customerSource.value,
  305. },
  306. {
  307. type: "select",
  308. label: "客户类型",
  309. prop: "status",
  310. itemWidth: 50,
  311. data: customerStatus.value,
  312. },
  313. {
  314. type: "select",
  315. label: "业务员",
  316. prop: "userId",
  317. itemWidth: 100,
  318. data: userList.value,
  319. clearable: true,
  320. disabled: isHighseas.value,
  321. },
  322. {
  323. type: "select",
  324. label: "客户标签",
  325. prop: "tags",
  326. itemWidth: 100,
  327. multiple: true,
  328. data: customerTag.value,
  329. style: {
  330. width: "100%",
  331. },
  332. },
  333. {
  334. type: "input",
  335. prop: "beneficiaryName",
  336. label: "Beneficiary Name",
  337. required: true,
  338. itemWidth: 50,
  339. itemType: "text",
  340. },
  341. {
  342. type: "input",
  343. prop: "beneficiaryAccountNumber",
  344. label: "Beneficiary Account Number",
  345. required: true,
  346. itemWidth: 50,
  347. itemType: "text",
  348. },
  349. {
  350. type: "input",
  351. prop: "beneficiaryBank",
  352. label: "Beneficiary Bank",
  353. required: true,
  354. itemWidth: 50,
  355. itemType: "text",
  356. },
  357. {
  358. type: "input",
  359. prop: "swiftCode",
  360. label: "Swift Code",
  361. required: true,
  362. itemWidth: 50,
  363. itemType: "text",
  364. },
  365. {
  366. type: "input",
  367. prop: "beneficiaryBankAddress",
  368. label: "Beneficiary Bank Address",
  369. required: true,
  370. itemWidth: 50,
  371. itemType: "text",
  372. },
  373. {
  374. type: "input",
  375. prop: "beneficiaryAddress",
  376. label: "Beneficiary Address",
  377. required: true,
  378. itemWidth: 50,
  379. itemType: "text",
  380. },
  381. {
  382. type: "title1",
  383. title: "联系人",
  384. },
  385. {
  386. type: "slot",
  387. slotName: "person",
  388. label: "客户联系人",
  389. },
  390. ];
  391. });
  392. const rules = ref({
  393. name: [{ required: true, message: "请输入客户名称", trigger: "blur" }],
  394. name2: [{ required: true, message: "请输入联系人", trigger: "blur" }],
  395. email: [{ required: true, message: "请输入电子邮箱", trigger: "blur" }],
  396. countryId: [{ required: true, message: "请选择国家", trigger: "change" }],
  397. source: [{ required: true, message: "请选择客户来源", trigger: "change" }],
  398. status: [{ required: true, message: "请选择类型", trigger: "change" }],
  399. });
  400. if (props.isPrivate) {
  401. rules.value.userId = [
  402. { required: true, message: "请选择业务员", trigger: "change" },
  403. ];
  404. }
  405. const clickAddPerson = () => {
  406. if (
  407. formData.data.customerUserList &&
  408. formData.data.customerUserList.length > 0
  409. ) {
  410. formData.data.customerUserList.push({
  411. name: "",
  412. email: "",
  413. });
  414. } else {
  415. formData.data.customerUserList = [
  416. {
  417. name: "",
  418. email: "",
  419. },
  420. ];
  421. }
  422. };
  423. const formPerson = reactive({
  424. data: {},
  425. });
  426. const rulesPerson = ref({
  427. name: [{ required: true, message: "请输入联系人", trigger: "blur" }],
  428. email: [{ required: true, message: "请输入电子邮箱", trigger: "blur" }],
  429. type: [{ required: true, message: "请选择类型", trigger: "change" }],
  430. contactNo: [{ required: true, message: "请输入联系号码", trigger: "blur" }],
  431. });
  432. const person = ref(null);
  433. const openPerson = ref(false);
  434. const moreIndex = ref(0);
  435. const clickInformationMore = (item, index) => {
  436. moreIndex.value = index;
  437. if (item.contactJson) {
  438. item.contact = JSON.parse(item.contactJson);
  439. } else {
  440. item.contact = [];
  441. }
  442. formPerson.data = proxy.deepClone(item);
  443. openPerson.value = true;
  444. };
  445. const clickDelete = (index) => {
  446. formData.data.customerUserList.splice(index, 1);
  447. };
  448. const clickAddMoreInformation = () => {
  449. if (formPerson.data.contact && formPerson.data.contact.length > 0) {
  450. formPerson.data.contact.push({
  451. type: "",
  452. contactNo: "",
  453. });
  454. } else {
  455. formPerson.data.contact = [
  456. {
  457. type: "",
  458. contactNo: "",
  459. },
  460. ];
  461. }
  462. };
  463. const clickInformationDelete = (index) => {
  464. formPerson.data.contact.splice(index, 1);
  465. };
  466. const submitPerson = () => {
  467. person.value.validate((valid) => {
  468. if (valid) {
  469. formPerson.data.contactJson = JSON.stringify(formPerson.data.contact);
  470. formData.data.customerUserList[moreIndex.value] = formPerson.data;
  471. openPerson.value = false;
  472. }
  473. });
  474. };
  475. const handleSubmit = () => {
  476. submit.value.handleSubmit(() => {
  477. if (
  478. formData.data.customerUserList &&
  479. formData.data.customerUserList.length > 0
  480. ) {
  481. formData.data.tag = formData.data.tags.join(",");
  482. loading.value = true;
  483. proxy.post("/customer/" + modalType.value, formData.data).then(
  484. () => {
  485. ElMessage({
  486. message: modalType.value == "add" ? "添加成功" : "编辑成功",
  487. type: "success",
  488. });
  489. proxy.$emit("refreshList");
  490. loading.value = false;
  491. },
  492. (err) => {
  493. console.log(err);
  494. loading.value = false;
  495. }
  496. );
  497. } else {
  498. ElMessage("请添加客户联系人");
  499. }
  500. });
  501. };
  502. const querySearch = (queryString, callback) => {
  503. proxy
  504. .post("/customer/page", {
  505. pageNum: 1,
  506. pageSize: 20,
  507. name: queryString,
  508. })
  509. .then((res) => {
  510. if (res.rows && res.rows.length > 0) {
  511. res.rows = res.rows.map((item) => {
  512. return {
  513. ...item,
  514. value: item.name,
  515. };
  516. });
  517. callback(res.rows);
  518. } else {
  519. callback([]);
  520. }
  521. });
  522. };
  523. defineExpose({
  524. handleSubmit,
  525. });
  526. </script>
  527. <style lang="scss" scoped>
  528. </style>