edit.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. <template>
  2. <el-drawer
  3. v-model="visible"
  4. title="修改客户关怀"
  5. direction="rtl"
  6. size="80%"
  7. @close="handleClose"
  8. destroy-on-close
  9. class="custom-drawer"
  10. >
  11. <div class="drawer-body" v-loading="loading">
  12. <el-form ref="careRef" :model="form" :rules="rules" label-width="100px" label-position="right">
  13. <div class="dialog-section no-border">
  14. <div class="section-title">个人资料</div>
  15. <el-row :gutter="20">
  16. <el-col :span="12">
  17. <el-form-item label="客户名称:" prop="customerName">
  18. <el-select
  19. v-model="form.customerName"
  20. placeholder="请选择"
  21. style="width: 100%"
  22. filterable
  23. remote
  24. :remote-method="remoteLoadCustomers"
  25. :loading="selectLoading"
  26. @focus="remoteLoadCustomers('')"
  27. @change="handleCustomerChange"
  28. >
  29. <el-option v-for="item in customerOptions" :key="item.value" :label="item.label" :value="item.label" />
  30. </el-select>
  31. </el-form-item>
  32. </el-col>
  33. <el-col :span="12">
  34. <el-form-item label="行业:" prop="profession">
  35. <el-select v-model="form.profession" placeholder="请选择" style="width: 100%" clearable>
  36. <el-option v-for="item in industryOptions" :key="item.id" :label="item.industryCategoryName" :value="item.industryCategoryName" />
  37. </el-select>
  38. </el-form-item>
  39. </el-col>
  40. </el-row>
  41. <el-row :gutter="20">
  42. <el-col :span="12">
  43. <el-form-item label="部门:" prop="department">
  44. <el-tree-select
  45. v-model="form.department"
  46. :data="deptOptions"
  47. :props="{ value: 'label', label: 'label', children: 'children' }"
  48. value-key="id"
  49. placeholder="请选择"
  50. check-strictly
  51. style="width: 100%"
  52. />
  53. </el-form-item>
  54. </el-col>
  55. <el-col :span="12">
  56. <el-form-item label="业务员:" prop="salesman">
  57. <el-select v-model="form.salesman" placeholder="请选择" style="width: 100%" clearable>
  58. <el-option v-for="item in staffOptions" :key="item.staffId" :label="item.staffName" :value="item.staffName" />
  59. </el-select>
  60. </el-form-item>
  61. </el-col>
  62. </el-row>
  63. <el-row :gutter="20">
  64. <el-col :span="12">
  65. <el-form-item label="联系人:" prop="contactPerson">
  66. <el-select
  67. v-model="form.contactPerson"
  68. placeholder="请选择"
  69. style="width: 100%"
  70. filterable
  71. clearable
  72. remote
  73. :remote-method="remoteSearchContacts"
  74. :loading="contactSearchLoading"
  75. @focus="onContactFocus"
  76. @change="handleContactChange"
  77. >
  78. <el-option v-for="item in contactOptions" :key="item.id" :label="item.label" :value="item.label" />
  79. </el-select>
  80. </el-form-item>
  81. </el-col>
  82. <el-col :span="12">
  83. <el-form-item label="手机:" prop="phone">
  84. <el-input v-model="form.phone" placeholder="请输入手机" />
  85. </el-form-item>
  86. </el-col>
  87. </el-row>
  88. <el-row :gutter="20">
  89. <el-col :span="12">
  90. <el-form-item label="固定电话:" prop="telephone">
  91. <el-input v-model="form.telephone" placeholder="请输入固定电话" />
  92. </el-form-item>
  93. </el-col>
  94. <el-col :span="12">
  95. <el-form-item label="关怀类型:" prop="concernType">
  96. <el-select v-model="form.concernType" placeholder="请选择" style="width: 100%">
  97. <el-option v-for="item in careTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
  98. </el-select>
  99. </el-form-item>
  100. </el-col>
  101. </el-row>
  102. <el-row :gutter="20">
  103. <el-col :span="12">
  104. <el-form-item label="金额:" prop="amount">
  105. <el-input-number
  106. v-model="form.amount"
  107. :precision="2"
  108. :step="0.01"
  109. :min="0"
  110. :controls="false"
  111. placeholder="请输入金额"
  112. class="amount-input"
  113. style="width: 100%"
  114. />
  115. </el-form-item>
  116. </el-col>
  117. <el-col :span="12">
  118. <el-form-item label="需求时间:" prop="requirementDate">
  119. <el-date-picker v-model="form.requirementDate" type="datetime" placeholder="请选择" style="width: 100%" value-format="YYYY-MM-DD HH:mm:ss" />
  120. </el-form-item>
  121. </el-col>
  122. </el-row>
  123. <el-row :gutter="20">
  124. <el-col :span="24">
  125. <el-form-item label="附件:" prop="fileNo">
  126. <fileUpload v-model="form.fileNo" :limit="5" :fileSize="10" :isShowTip="false" />
  127. </el-form-item>
  128. </el-col>
  129. </el-row>
  130. </div>
  131. <div class="dialog-section no-border no-margin">
  132. <el-form-item label="礼品描述:" prop="giftDesc">
  133. <el-input v-model="form.giftDesc" type="textarea" :rows="4" placeholder="请输入内容" />
  134. </el-form-item>
  135. <el-form-item label="关怀理由:" prop="concernArgument">
  136. <el-input v-model="form.concernArgument" type="textarea" :rows="4" placeholder="请输入内容" />
  137. </el-form-item>
  138. </div>
  139. </el-form>
  140. </div>
  141. <template #footer>
  142. <div class="drawer-footer">
  143. <el-button type="primary" @click="submitForm">确认</el-button>
  144. <el-button @click="handleClose">取消</el-button>
  145. </div>
  146. </template>
  147. </el-drawer>
  148. </template>
  149. <script setup name="CustomerCareEdit">
  150. import { ref, reactive, onMounted, getCurrentInstance, toRefs } from 'vue';
  151. import { useRouter, useRoute } from 'vue-router';
  152. import { getCare, updateCare } from "@/api/customer/crmCare";
  153. import { listCustomerInfo, getCustomerInfo } from "@/api/customer/customerInfo/";
  154. import { listContact } from "@/api/customer/crmContact";
  155. import { listIndustryCategory } from "@/api/customer/industryCategory";
  156. import { selectStaffOptionList } from "@/api/customer/crmStaff";
  157. import { deptTreeSelect } from "@/api/system/user/index";
  158. const proxy = getCurrentInstance().proxy;
  159. const { care_type: careTypeOptions } = toRefs(reactive(proxy.useDict("care_type")));
  160. const router = useRouter();
  161. const route = useRoute();
  162. const visible = ref(false);
  163. const loading = ref(false);
  164. const selectLoading = ref(false);
  165. const contactSearchLoading = ref(false);
  166. const customerOptions = ref([]);
  167. const contactOptions = ref([]);
  168. const industryOptions = ref([]);
  169. const staffOptions = ref([]);
  170. const deptOptions = ref([]);
  171. const form = reactive({
  172. id: undefined,
  173. customerId: undefined,
  174. customerName: '',
  175. profession: '',
  176. department: '',
  177. salesman: '',
  178. contactPerson: '',
  179. phone: '',
  180. telephone: '',
  181. concernType: '',
  182. amount: undefined,
  183. requirementDate: undefined,
  184. fileNo: '',
  185. giftDesc: '',
  186. concernArgument: '',
  187. auditStatus: 0
  188. });
  189. const rules = reactive({
  190. customerName: [{ required: true, message: "客户名称不能为空", trigger: "change" }],
  191. profession: [{ required: true, message: "行业不能为空", trigger: "change" }],
  192. department: [{ required: true, message: "部门不能为空", trigger: "change" }],
  193. salesman: [{ required: true, message: "业务员不能为空", trigger: "change" }],
  194. contactPerson: [{ required: true, message: "联系人不能为空", trigger: "change" }],
  195. phone: [{ required: true, message: "手机不能为空", trigger: "blur" }],
  196. telephone: [{ required: true, message: "固定电话不能为空", trigger: "blur" }],
  197. concernType: [{ required: true, message: "关怀类型不能为空", trigger: "change" }],
  198. amount: [{ required: true, message: "金额不能为空", trigger: "blur" }],
  199. giftDesc: [{ required: true, message: "礼品描述不能为空", trigger: "blur" }],
  200. concernArgument: [{ required: true, message: "关怀理由不能为空", trigger: "blur" }]
  201. });
  202. /** 获取详情 */
  203. function getDetail() {
  204. const id = route.query.id;
  205. if (id) {
  206. loading.value = true;
  207. getCare(id).then(response => {
  208. Object.assign(form, response.data);
  209. // 预填充当前选中的客户和联系人下拉选项,防止回显失败
  210. customerOptions.value = [{ label: form.customerName, value: form.customerName, id: form.customerId }];
  211. contactOptions.value = [{ label: form.contactPerson, value: form.contactPerson }];
  212. loading.value = false;
  213. // 加载该客户下的其他联系人
  214. remoteSearchContacts('');
  215. }).catch(() => {
  216. loading.value = false;
  217. });
  218. }
  219. }
  220. /** 远程加载客户列表 */
  221. const remoteLoadCustomers = (query) => {
  222. selectLoading.value = true;
  223. listCustomerInfo({ customerName: query || undefined, pageSize: 20 }).then(res => {
  224. customerOptions.value = (res.rows || []).map(item => ({
  225. label: item.customerName,
  226. value: item.customerName,
  227. id: item.id,
  228. ...item
  229. }));
  230. selectLoading.value = false;
  231. }).catch(() => {
  232. selectLoading.value = false;
  233. });
  234. };
  235. /** 客户选中处理 */
  236. const handleCustomerChange = async (val) => {
  237. const customer = customerOptions.value.find(item => item.label === val);
  238. if (customer) {
  239. form.customerId = customer.id;
  240. form.contactPerson = '';
  241. form.phone = '';
  242. form.telephone = '';
  243. try {
  244. const res = await getCustomerInfo(customer.id);
  245. const detail = res.data;
  246. if (detail) {
  247. form.profession = detail.industryCategory || '';
  248. if (detail.customerSalesInfoVo) {
  249. form.salesman = detail.customerSalesInfoVo.salesPerson || '';
  250. form.department = detail.customerSalesInfoVo.belongingDepartment || '';
  251. }
  252. }
  253. } catch (error) {}
  254. remoteSearchContacts('');
  255. }
  256. };
  257. /** 远程搜索联系人 */
  258. const remoteSearchContacts = (query) => {
  259. contactSearchLoading.value = true;
  260. const params = { pageSize: 50 };
  261. if (form.customerId) params.customerId = form.customerId;
  262. if (query) params.contactName = query;
  263. listContact(params).then(res => {
  264. contactOptions.value = (res.rows || []).map(item => ({
  265. label: item.contactName,
  266. value: item.contactName,
  267. id: item.id,
  268. ...item
  269. }));
  270. }).finally(() => {
  271. contactSearchLoading.value = false;
  272. });
  273. };
  274. const onContactFocus = () => {
  275. if (contactOptions.value.length === 0) remoteSearchContacts('');
  276. };
  277. const handleContactChange = (val) => {
  278. if (!val) {
  279. form.phone = '';
  280. form.telephone = '';
  281. return;
  282. }
  283. const contact = contactOptions.value.find(item => item.label === val);
  284. if (contact) {
  285. form.phone = contact.phone || '';
  286. form.telephone = contact.officePhone || '';
  287. }
  288. };
  289. /** 提交按钮 */
  290. function submitForm() {
  291. proxy.$refs["careRef"].validate(valid => {
  292. if (valid) {
  293. updateCare(form).then(() => {
  294. proxy.$modal.msgSuccess("修改成功");
  295. handleClose(true);
  296. });
  297. }
  298. });
  299. }
  300. /** 关闭抽屉 */
  301. function handleClose(refresh = false) {
  302. visible.value = false;
  303. router.back();
  304. }
  305. /** 加载基础选项 */
  306. const initBaseOptions = () => {
  307. listIndustryCategory().then(res => { industryOptions.value = res.data || []; });
  308. selectStaffOptionList().then(res => { staffOptions.value = res.data || []; });
  309. deptTreeSelect().then(res => {
  310. const data = res.data || [];
  311. deptOptions.value = proxy.handleTree(data, "id");
  312. });
  313. };
  314. onMounted(() => {
  315. getDetail();
  316. initBaseOptions();
  317. remoteLoadCustomers('');
  318. });
  319. </script>
  320. <style scoped lang="scss">
  321. .drawer-body { padding: 0 30px; }
  322. .dialog-section {
  323. padding-bottom: 5px; margin-bottom: 5px;
  324. &.no-border { border-bottom: none; }
  325. &.no-margin { margin-bottom: 0; padding-bottom: 0; }
  326. .section-title {
  327. font-size: 15px; color: #333;
  328. margin-bottom: 25px; margin-top: 10px;
  329. }
  330. }
  331. .static-text {
  332. color: #606266;
  333. font-size: 14px;
  334. }
  335. :deep(.el-form-item) {
  336. margin-bottom: 22px;
  337. }
  338. .drawer-footer {
  339. padding: 15px 25px;
  340. text-align: right;
  341. border-top: 1px solid #ebeef5;
  342. }
  343. :deep(.amount-input .el-input__inner) {
  344. text-align: left !important;
  345. }
  346. /* 强制所有字体不加粗 */
  347. :deep(*) {
  348. font-weight: 400 !important;
  349. }
  350. .section-title {
  351. font-weight: 400 !important;
  352. }
  353. </style>