index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. <template>
  2. <div>
  3. <PlusPage
  4. ref="plusPageInstance"
  5. :columns="tableConfig"
  6. :request="getList"
  7. :is-card="true"
  8. :search="{
  9. labelWidth: 100,
  10. showNumber: 3
  11. }"
  12. :table="{
  13. actionBar: { buttons, type: 'link', width: 180 },
  14. adaptive: { offsetBottom: 50 },
  15. isSelection: true,
  16. rowKey: 'id',
  17. onSelectionChange: handleSelectionChange
  18. }"
  19. :pageInfoMap="{ page: 'pageNum', pageSize: 'pageSize' }"
  20. />
  21. <!-- 弹窗编辑 -->
  22. <PlusDialogForm
  23. ref="dialogForm"
  24. v-model="form"
  25. v-model:visible="dialogVisible"
  26. :form="{
  27. columns,
  28. labelPosition: 'left',
  29. labelWidth: 100,
  30. rules
  31. }"
  32. :dialog="{ title: dialogTitle + '菜单', width: 600, confirmLoading }"
  33. @confirm="handleSubmit"
  34. @close="handleClose"
  35. />
  36. <!-- 跟进状态弹窗 -->
  37. <plusDialog
  38. v-model="detailsVisible"
  39. :hasFooter="false"
  40. title="跟进状态"
  41. width="600"
  42. >
  43. <plus-descriptions
  44. :column="4"
  45. :data="detailForm"
  46. :columns="detailsColumns"
  47. :border="false"
  48. />
  49. <el-timeline>
  50. <el-timeline-item
  51. v-for="item in detailForm.list"
  52. :key="item.id"
  53. :timestamp="item.createTime"
  54. >
  55. <el-card>
  56. <el-row>
  57. <el-col :span="8">
  58. <el-rate v-model="item.starLevel" disabled />
  59. </el-col>
  60. <el-col :span="16">
  61. <el-tag>{{ item.remark }}</el-tag>
  62. </el-col>
  63. </el-row>
  64. </el-card>
  65. </el-timeline-item>
  66. </el-timeline>
  67. </plusDialog>
  68. <!-- 重新分配弹窗 -->
  69. <PlusDialogForm
  70. ref="resetFormDialog"
  71. v-model="resetForm"
  72. v-model:visible="resetVisible"
  73. :form="{
  74. columns: resetColumns,
  75. labelWidth: 100,
  76. rules: resetRules
  77. }"
  78. title="重新分配"
  79. :dialog="{
  80. width: 400,
  81. confirmLoading
  82. }"
  83. @confirm="handleResetAccount"
  84. @close="handleClose"
  85. />
  86. </div>
  87. </template>
  88. <script lang="ts" setup>
  89. import {
  90. computed,
  91. onMounted,
  92. reactive,
  93. ref,
  94. resolveDirective,
  95. toRefs
  96. } from "vue";
  97. import type { FormRules } from "element-plus";
  98. import { ElMessage, ElMessageBox } from "element-plus";
  99. import {
  100. type FieldValues,
  101. type PlusColumn,
  102. PlusDescriptions,
  103. PlusDialog,
  104. PlusDialogForm,
  105. PlusPage,
  106. PlusPageInstance,
  107. useTable
  108. } from "plus-pro-components";
  109. import { useRouter } from "vue-router";
  110. import {
  111. getMerchantOrderInfoAllList,
  112. getMyOrderInfoAllList,
  113. merchantFollowInfoAllocationAccount,
  114. merchantFollowInfoList,
  115. merchantFollowInfoReliveOrder,
  116. updateStartLevel
  117. } from "@/api/order";
  118. import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
  119. import { isString } from "@pureadmin/utils";
  120. import { getChildAccount } from "@/api/childAccount";
  121. defineOptions({
  122. name: "OrderMy"
  123. });
  124. const router = useRouter();
  125. const plusPageInstance = ref<PlusPageInstance | null>(null);
  126. const getList = async (query: Record<string, any>) => {
  127. let res = await getMyOrderInfoAllList(query);
  128. return {
  129. data: res.data.list,
  130. total: res.data.total
  131. };
  132. };
  133. onMounted(() => {
  134. getChildAccountList();
  135. });
  136. // 重新请求列表接口
  137. const refresh = () => {
  138. plusPageInstance.value?.getList();
  139. };
  140. const dialogTitle = computed(() => (state.isCreate ? "新增" : "编辑"));
  141. const multipleSelection = ref([]);
  142. const handleSelectionChange = (val: any[]) => {
  143. multipleSelection.value = val;
  144. };
  145. const handleReliveOrder = () => {
  146. if (multipleSelection.value.length === 0) {
  147. ElMessage.warning("请选择要解除分配的订单");
  148. return;
  149. }
  150. ElMessageBox.confirm("确认解除分配?", "提示").then(async () => {
  151. try {
  152. let res = await merchantFollowInfoReliveOrder({
  153. orderIds: multipleSelection.value.map((item: any) => item.id)
  154. });
  155. if (res.code === 0) {
  156. ElMessage.success("解除分配成功");
  157. refresh();
  158. }
  159. } catch (e) {
  160. ElMessage.error("删除失败");
  161. }
  162. });
  163. };
  164. // 表格数据
  165. const tableConfig: PlusColumn[] = [
  166. {
  167. label: "订单号",
  168. tableColumnProps: {
  169. showOverflowTooltip: true
  170. },
  171. width: 150,
  172. prop: "orderNo"
  173. },
  174. {
  175. label: "客户姓名",
  176. prop: "userName"
  177. },
  178. {
  179. label: "性别",
  180. prop: "userSex",
  181. width: 60,
  182. hideInSearch: true
  183. },
  184. {
  185. label: "客户星级",
  186. prop: "star",
  187. valueType: "rate",
  188. editable: true,
  189. width: 140,
  190. fieldProps: {
  191. disabled: true
  192. },
  193. hideInSearch: true
  194. },
  195. {
  196. label: "电话",
  197. prop: "maskPhone",
  198. width: 100,
  199. hideInSearch: true
  200. },
  201. /*{
  202. label: "微信",
  203. prop: "wxCode",
  204. tableColumnProps: {
  205. showOverflowTooltip: true
  206. },
  207. hideInSearch: true
  208. },
  209. {
  210. label: "优先联系方式",
  211. prop: "headContractType",
  212. hideInSearch: true
  213. },*/
  214. {
  215. label: "申请产品",
  216. prop: "planName",
  217. hideInSearch: true
  218. },
  219. {
  220. label: "需求资金",
  221. prop: "loanAmount",
  222. hideInSearch: true
  223. },
  224. {
  225. label: "贷款期限",
  226. prop: "loanTerm",
  227. hideInSearch: true
  228. },
  229. {
  230. label: "申请时间",
  231. prop: "applyTime",
  232. width: 170,
  233. hideInSearch: true
  234. },
  235. /*{
  236. label: "分配子账号",
  237. prop: "follower",
  238. width: 120,
  239. hideInSearch: true
  240. },*/
  241. {
  242. label: "状态",
  243. prop: "followStatus",
  244. valueType: "select",
  245. options: [
  246. { label: "未跟进", value: 0 },
  247. { label: "跟进", value: 4 }
  248. ],
  249. hideInSearch: true
  250. },
  251. {
  252. label: "备注",
  253. prop: "wechat",
  254. hideInSearch: true
  255. }
  256. ];
  257. /*--------------------表单--------------------*/
  258. // 表单实例
  259. const dialogForm = ref(null);
  260. interface State {
  261. dialogVisible: boolean;
  262. detailsVisible: boolean;
  263. resetVisible: boolean;
  264. confirmLoading: boolean;
  265. selectedIds: number[];
  266. isCreate: boolean;
  267. form: {};
  268. detailForm: {
  269. list: any;
  270. };
  271. resetForm: {};
  272. rules: FormRules;
  273. resetRules: FormRules;
  274. }
  275. const state = reactive<State>({
  276. dialogVisible: false,
  277. detailsVisible: false,
  278. resetVisible: false,
  279. confirmLoading: false,
  280. selectedIds: [],
  281. isCreate: false,
  282. form: {},
  283. detailForm: {
  284. list: []
  285. },
  286. resetForm: {},
  287. rules: {
  288. starLevel: [
  289. { required: true, message: "请选择客户星级", trigger: "change" }
  290. ]
  291. },
  292. resetRules: {
  293. accountId: [
  294. { required: true, message: "请选择分配子账号", trigger: "change" }
  295. ]
  296. }
  297. });
  298. const columns: PlusColumn[] = [
  299. {
  300. label: "客户星级",
  301. prop: "starLevel",
  302. valueType: "select",
  303. tooltip: {
  304. content:
  305. "<span>客户星级说明</span></br>" +
  306. "<span>0星:未接通</span></br>" +
  307. "<span>1星:接通但无办理意向</span></br>" +
  308. "<span>2星:有意向但无可贷点</span></br>" +
  309. "<span>3星:有可贷点但资质一般</span></br>" +
  310. "<span>4星:有可贷点且条件较好</span></br>" +
  311. "<span>5星:马上需要或条件优质</span></br>",
  312. rawContent: true
  313. },
  314. options: [
  315. { label: "1星", value: 1 },
  316. { label: "2星", value: 2 },
  317. { label: "3星", value: 3 },
  318. { label: "4星", value: 4 },
  319. { label: "5星", value: 5 }
  320. ]
  321. },
  322. {
  323. label: "备注",
  324. prop: "remark",
  325. valueType: "input",
  326. fieldProps: {
  327. type: "textarea",
  328. rows: 4,
  329. maxlength: 200,
  330. showWordLimit: true
  331. }
  332. }
  333. ];
  334. const detailsColumns: PlusColumn[] = [
  335. {
  336. label: "姓名:",
  337. prop: "userName"
  338. },
  339. {
  340. label: "需求资金:",
  341. prop: "loanAmount"
  342. },
  343. {
  344. label: "年龄:",
  345. prop: "age"
  346. },
  347. {
  348. label: "需求周期:",
  349. prop: "loanTerm"
  350. }
  351. ];
  352. const childAccountList = ref<any[]>([]);
  353. const getChildAccountList = async () => {
  354. let res = await getChildAccount();
  355. childAccountList.value = res.data;
  356. };
  357. const resetColumns: PlusColumn[] = [
  358. {
  359. label: "分配子账号",
  360. prop: "accountId",
  361. valueType: "select",
  362. options: computed(() => childAccountList.value),
  363. optionsMap: {
  364. label: "contractName",
  365. value: "id"
  366. }
  367. }
  368. ];
  369. const handleSubmit = async (values: FieldValues) => {
  370. confirmLoading.value = true;
  371. try {
  372. let params = form.value;
  373. console.log(params);
  374. let res = await updateStartLevel(params);
  375. if (res.code === 0) {
  376. ElMessage.success("修改成功");
  377. confirmLoading.value = false;
  378. dialogVisible.value = false;
  379. refresh();
  380. } else {
  381. ElMessage.error(res.msg);
  382. }
  383. } finally {
  384. confirmLoading.value = false;
  385. }
  386. };
  387. const handleResetAccount = async (values: FieldValues) => {
  388. confirmLoading.value = true;
  389. try {
  390. let params = resetForm.value;
  391. console.log(params);
  392. let res = await merchantFollowInfoAllocationAccount(params);
  393. if (res.code === 0) {
  394. ElMessage.success("重新分配成功");
  395. resetVisible.value = false;
  396. refresh();
  397. } else {
  398. ElMessage.error(res.msg);
  399. }
  400. } catch (e) {
  401. ElMessage.error("重新分配失败");
  402. } finally {
  403. confirmLoading.value = false;
  404. }
  405. };
  406. const handleClose = () => {
  407. // 重置表单校验状态
  408. console.log(dialogForm.value.formInstance);
  409. };
  410. const { buttons } = useTable();
  411. const perms = resolveDirective("perms");
  412. const handleReset = () => {
  413. if (multipleSelection.value.length === 0) {
  414. ElMessage.warning("请选择要重新分配的订单");
  415. return;
  416. }
  417. resetForm.value = {};
  418. resetForm.value.id = multipleSelection.value.map((item: any) => item.id);
  419. console.log(resetForm.value);
  420. resetVisible.value = true;
  421. };
  422. buttons.value = [
  423. {
  424. // 修改
  425. text: "详情",
  426. code: "edit",
  427. // props v0.1.16 版本新增函数类型
  428. props: {
  429. type: "primary"
  430. },
  431. onClick(val) {
  432. let params = {
  433. id: val.row.id,
  434. orderNo: val.row.orderNo
  435. };
  436. Object.keys(params).forEach(param => {
  437. if (!isString(params[param])) {
  438. params[param] = params[param].toString();
  439. }
  440. });
  441. // 保存信息到标签页
  442. useMultiTagsStoreHook().handleTags("push", {
  443. path: `/order/order-loan/detail`,
  444. name: "OrderLoanDetail",
  445. query: params,
  446. meta: {
  447. title: `订单详情`,
  448. // 如果使用的是非国际化精简版title可以像下面这么写
  449. // title: `No.${index} - 详情信息`,
  450. // 最大打开标签数
  451. dynamicLevel: 1
  452. }
  453. });
  454. // 路由跳转
  455. router.push({ name: "OrderLoanDetail", query: params });
  456. }
  457. },
  458. {
  459. // 跟进
  460. text: "跟进",
  461. props: {
  462. type: "primary"
  463. },
  464. onClick(val) {
  465. form.value = {};
  466. form.value.orderId = val.row.orderNo;
  467. dialogVisible.value = true;
  468. }
  469. },
  470. {
  471. // 修改
  472. text: "跟进记录",
  473. props: {
  474. type: "primary"
  475. },
  476. onClick(val: any) {
  477. console.log(val.row);
  478. detailForm.value = val.row;
  479. detailForm.value.list = [];
  480. merchantFollowInfoList({ orderNo: val.row.orderNo }).then(res => {
  481. detailForm.value.list = res.data;
  482. });
  483. detailsVisible.value = true;
  484. }
  485. }
  486. ];
  487. const {
  488. form,
  489. detailForm,
  490. resetForm,
  491. confirmLoading,
  492. rules,
  493. resetRules,
  494. dialogVisible,
  495. detailsVisible,
  496. resetVisible
  497. } = toRefs(state);
  498. </script>