index.vue 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441
  1. <template>
  2. <div class="pageIndexClass">
  3. <div class="content">
  4. <byTable :source="sourceList.data" :pagination="sourceList.pagination" :config="config" :loading="loading" :selectConfig="selectConfig"
  5. :statConfig="statConfig" :onMoreSearch="false" @moreSearch="clickMoreSearch" highlight-current-row :action-list="[
  6. {
  7. text: '新建销售合同',
  8. action: () => newContract(),
  9. },
  10. ]" @get-list="getList">
  11. <template #code="{ item }">
  12. <div style="width: 100%">
  13. <a style="color: #409eff; cursor: pointer; word-break: break-all" @click="openDetails(item)">{{ item.code }}</a>
  14. </div>
  15. </template>
  16. <template #isSettled="{ item }">
  17. <div>
  18. <span style="padding: 4px" :class="[item.isSettled == 1 ? 'active' : '']">
  19. {{
  20. proxy.dictValueLabel(item.isSettled, isSettled)
  21. }}</span>
  22. </div>
  23. </template>
  24. <template #amount="{ item }">
  25. <div>
  26. <span style="padding-right: 4px">{{ item.currency }}</span>
  27. <span>{{ moneyFormat(item.amount, 2) }}</span>
  28. </div>
  29. </template>
  30. <template #buyCorporationName="{ item }">
  31. <div style="width: 100%">
  32. <a style="color: #409eff; cursor: pointer" @click="clickCorporationName(item)">{{ item.buyCorporationName }}</a>
  33. </div>
  34. </template>
  35. <template #product="{item}">
  36. <div style="width: 100%">
  37. <el-popover placement="top-start" :width="400" trigger="hover" @show="onShowProductData(item)">
  38. <div style="display:flex;margin-bottom:20px;align-items:center" v-for="i in productData" :key="i.id">
  39. <div style="width:60px">
  40. <img :src="i.productImgUrl" alt="" class="pic" @click="handleClickFile(i.productImgUrl)">
  41. </div>
  42. <div style="calc(100% - 60px)">
  43. <div>产品编码:{{i.productCode}}</div>
  44. <div>产品名称:{{i.productName}}</div>
  45. <div>产品数量:{{i.quantity}}</div>
  46. </div>
  47. </div>
  48. <template #reference>
  49. <div style="display:flex;height:65px;position:relative;top:15px">
  50. <div v-for="(product,index) in item.contractProductList" :key="product.id" style="margin-right:10px;">
  51. <el-badge :value="product.quantity" :min="0" :max="999999" v-if="index<3">
  52. <img :src="product.productImgUrl" class="pic" @click="handleClickFile(product.productImgUrl)">
  53. </el-badge>
  54. </div>
  55. </div>
  56. </template>
  57. </el-popover>
  58. </div>
  59. </template>
  60. <template #prodTag="{ item }">
  61. <div style="width: 100%">
  62. <el-icon :size="16" style="cursor:pointer;margin-right: 5px;position:relative;top:5px" color="#409EFF" @click="handleEditTag(item)">
  63. <Edit />
  64. </el-icon> <el-tag style="margin-right: 8px" type="success" v-for="(tag, index) in item.prodTags" closable :key="index"
  65. @close="prodTagClose(index, item)">
  66. {{ dictKeyValue(tag, contractTag) }}
  67. </el-tag>
  68. </div>
  69. </template>
  70. <template #tags="{ item }">
  71. <div style="width: 100%">
  72. <el-tag style="margin-right: 8px" type="success" v-for="(tag, index) in item.tags" closable :key="index" @close="tagClose(tag, item)">
  73. {{ dictValueLabel(tag, customerTag) }}
  74. </el-tag>
  75. <template v-if="item.tags.length !== customerTag.length">
  76. <el-select v-if="item.addTagShow" v-model="addTag" style="width: 100%" @change="
  77. (val) => {
  78. return changeTag(val, item);
  79. }
  80. ">
  81. <el-option v-for="tag in customerTag" :key="tag.value" :label="tag.label" :value="tag.value"
  82. :disabled="judgeTagSelect(item.tags, tag.value)" />
  83. </el-select>
  84. <el-tag style="cursor: pointer" type="success" @click="showSelect(item)" v-else>
  85. +
  86. </el-tag>
  87. </template>
  88. </div>
  89. </template>
  90. <template #advanceRatio="{ item }">
  91. <div>
  92. <span>{{ moneyFormat(item.advanceRatio, 2) }}%</span>
  93. </div>
  94. </template>
  95. <template #scale="{ item }">
  96. <div>
  97. {{ computeScale(item) }}
  98. </div>
  99. </template>
  100. </byTable>
  101. </div>
  102. <el-dialog title="打印" v-if="openPrint" v-model="openPrint" width="920">
  103. <ContractPDFOne :rowData="rowData"></ContractPDFOne>
  104. <!-- <ContractPDFOneNew :rowData="rowData" ref="PdfDom"></ContractPDFOneNew> -->
  105. <!-- <template #footer>
  106. <el-button @click="openPrint = false" size="default">取消</el-button>
  107. <el-button type="primary" v-print="printObj" size="default">打印</el-button>
  108. <el-button type="primary" @click="clickDownload()" size="default">下载PDF</el-button>
  109. <el-button type="primary" @click="exportExcel()" size="default">导出Excel</el-button>
  110. </template> -->
  111. </el-dialog>
  112. <el-dialog title="交接单" v-if="openHandoverSlip" v-model="openHandoverSlip" width="600">
  113. <byForm :formConfig="formConfig" :formOption="formOption" v-model="handoverSlipForm">
  114. <template #file>
  115. <div style="width: 100%">
  116. <el-upload v-model:fileList="handoverSlipForm.fileList" action="https://winfaster.obs.cn-south-1.myhuaweicloud.com" :data="uploadData"
  117. multiple :before-upload="uploadFile" :on-success="handleSuccess" :on-preview="onPreviewFile">
  118. <el-button type="primary" plain>选择</el-button>
  119. </el-upload>
  120. </div>
  121. </template>
  122. <template #indication>
  123. <div style="width: 100%">
  124. <el-upload v-model:fileList="handoverSlipForm.packageFileList" action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
  125. :data="indicationUploadData" multiple :before-upload="indicationUploadFile" :on-success="handleSuccess"
  126. :on-preview="onPreviewFile">
  127. <el-button type="primary" plain>选择</el-button>
  128. </el-upload>
  129. </div>
  130. </template>
  131. </byForm>
  132. <template #footer>
  133. <el-button @click="openHandoverSlip = false" size="default">关 闭</el-button>
  134. <el-button type="primary" @click="submitHandoverSlip()" size="default">确 定</el-button>
  135. </template>
  136. </el-dialog>
  137. <el-dialog title="合同详情" v-if="openDetailsDialog" v-model="openDetailsDialog" width="1100">
  138. <ContractDetails :contractId="currentContractId"></ContractDetails>
  139. </el-dialog>
  140. <el-dialog :title="`售后记录`" v-if="openRecords" v-model="openRecords" width="600">
  141. <div style="padding-left: 50px; margin-bottom: 20px">
  142. <el-button type="primary" plain @click="handleClickAddRecord()">添加记录</el-button>
  143. </div>
  144. <el-timeline>
  145. <el-timeline-item v-for="(activity, index) in recordsData" :key="index">
  146. <div style="
  147. width: 100%;
  148. display: flex;
  149. justify-content: space-between;
  150. color: #bfb9b9;
  151. ">
  152. <div>售后时间:{{ activity.documentaryTime }}</div>
  153. <div>{{ activity.userName }}</div>
  154. </div>
  155. <div style="width: 100%; margin-top: 8px">
  156. 售后记录:{{ activity.documentaryRemark }}
  157. </div>
  158. <div style="width: 100%; margin-top: 8px" v-if="activity.fileList && activity.fileList.length > 0">
  159. <div v-for="(item, index) in activity.fileList" :key="index">
  160. <div style="cursor: pointer; color: #409eff" @click="openFile(item)">
  161. {{ item.fileName }}
  162. </div>
  163. </div>
  164. </div>
  165. </el-timeline-item>
  166. </el-timeline>
  167. <template #footer>
  168. <el-button @click="openRecords = false" size="default">关 闭</el-button>
  169. </template>
  170. </el-dialog>
  171. <el-dialog :title="`添加售后记录`" v-if="openAddRecords" v-model="openAddRecords" width="600">
  172. <byForm :formConfig="recordsFormConfig" :formOption="formOption" v-model="formData.recordsFormData" :rules="recordsRules" ref="recordsForm"
  173. v-loading="formLoading">
  174. <template #file>
  175. <div style="width: 100%">
  176. <el-upload v-model:fileList="formData.recordsFormData.fileList" action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
  177. :data="uploadData" multiple :before-upload="uploadFile" :on-success="handleSuccess" :on-preview="onPreviewFile">
  178. <el-button type="primary" plain>选择</el-button>
  179. </el-upload>
  180. </div>
  181. </template>
  182. </byForm>
  183. <template #footer>
  184. <el-button @click="openAddRecords = false" size="default">关 闭</el-button>
  185. <el-button type="primary" @click="submitRecords()" size="default">确 定</el-button>
  186. </template>
  187. </el-dialog>
  188. <el-dialog :title="'高级检索'" v-model="moreSearchDialog" width="500px" destroy-on-close>
  189. <byForm :formConfig="formSearchConfig" :formOption="formOption" v-model="sourceList.pagination">
  190. </byForm>
  191. <template #footer>
  192. <el-button @click="moreSearchReset" size="default">重置</el-button>
  193. <el-button @click="moreSearchQuery" type="primary" size="default" v-debounce>搜索</el-button>
  194. </template>
  195. </el-dialog>
  196. <el-dialog :title="'下发生产'" v-model="productionDialog" width="700px" destroy-on-close>
  197. <byForm :formConfig="productionFormConfig" :formOption="formOption" v-model="formData.data" :rules="productionRules" ref="productionFormDom"
  198. v-loading="formLoading">
  199. <template #companyName>
  200. <div style="width:100%">
  201. {{formData.data.companyName}}
  202. </div>
  203. </template>
  204. </byForm>
  205. <template #footer>
  206. <el-button @click="productionDialog =false" size="default">取 消</el-button>
  207. <el-button @click="submitProduction" type="primary" size="default" v-debounce>下 发</el-button>
  208. </template>
  209. </el-dialog>
  210. <el-dialog :title="'生产指示'" v-model="tagDialog" width="700px" destroy-on-close>
  211. <byForm :formConfig="tagFormConfig" :formOption="formOption" v-model="formData.tagData" :rules="tagRules" ref="tagFormDom"
  212. v-loading="formLoading">
  213. </byForm>
  214. <template #footer>
  215. <el-button @click="tagDialog =false" size="default" v-debounce>取 消</el-button>
  216. <el-button @click="submitTag" type="primary" size="default" v-debounce>提 交</el-button>
  217. </template>
  218. </el-dialog>
  219. </div>
  220. </template>
  221. <script setup>
  222. import { computed, ref } from "vue";
  223. import byTable from "@/components/byTable/index";
  224. import byForm from "@/components/byForm/index";
  225. import useUserStore from "@/store/modules/user";
  226. import { ElMessage, ElMessageBox } from "element-plus";
  227. import ContractDetails from "@/components/contractCom/contractDetails.vue";
  228. import ContractPDFOne from "@/components/PDF/contractPDFOne.vue";
  229. import ContractPDFOneNew from "@/components/PDF/contractPDFOneNew.vue";
  230. import $bus from "@/bus/index.js";
  231. const route = useRoute();
  232. const contractTag = computed(
  233. () => proxy.useUserStore().allDict["contract_prod_tag"]
  234. );
  235. const { proxy } = getCurrentInstance();
  236. const accountCurrency = ref([]);
  237. const tradeMethods = ref([]);
  238. const corporationList = ref([]);
  239. const customerList = ref([]);
  240. const userList = ref([]);
  241. const companyData = ref([]);
  242. const isSettled = ref([
  243. {
  244. label: "已结清",
  245. value: "1",
  246. },
  247. {
  248. label: "未结清",
  249. value: "0",
  250. },
  251. ]);
  252. const shippingMethod = ref([]);
  253. const customerTag = ref([]);
  254. const openDetailsDialog = ref(false);
  255. const status = ref([
  256. {
  257. label: "草稿",
  258. value: 0,
  259. },
  260. {
  261. label: "审批中",
  262. value: 10,
  263. },
  264. {
  265. label: "驳回",
  266. value: 20,
  267. },
  268. {
  269. label: "审批通过",
  270. value: 30,
  271. },
  272. {
  273. label: "变更中",
  274. value: 60,
  275. },
  276. {
  277. label: "已变更",
  278. value: 70,
  279. },
  280. {
  281. label: "作废",
  282. value: 88,
  283. },
  284. {
  285. label: "终止",
  286. value: 99,
  287. },
  288. ]);
  289. const sourceList = ref({
  290. data: [],
  291. pagination: {
  292. total: 0,
  293. pageNum: 1,
  294. pageSize: 10,
  295. keyword: "",
  296. status: "",
  297. companyId: "",
  298. userId: "",
  299. isSettled: "",
  300. beginTime: "",
  301. endTime: "",
  302. },
  303. });
  304. const loading = ref(false);
  305. const selectConfig = computed(() => {
  306. return [
  307. {
  308. label: "审批状态",
  309. prop: "status",
  310. data: status.value,
  311. },
  312. {
  313. label: "生产公司",
  314. prop: "companyId",
  315. data: companyData.value,
  316. },
  317. {
  318. label: "业务员",
  319. prop: "userId",
  320. data: userList.value,
  321. },
  322. {
  323. label: "是否已结清",
  324. prop: "isSettled",
  325. data: isSettled.value,
  326. },
  327. {
  328. type: "time",
  329. label: "创建时间",
  330. placeholder: "开始日期",
  331. prop: "beginTime",
  332. placeholderOne: "结束日期",
  333. propOne: "endTime",
  334. },
  335. ];
  336. });
  337. const headerData = ref({});
  338. const statConfig = computed(() => [
  339. // {
  340. // label: "统计",
  341. // data: [
  342. // //一个卡牌多数据配置
  343. // {
  344. // label: "订单统计(CNY)",
  345. // type: 2,
  346. // data: [
  347. // {
  348. // label: "订单数",
  349. // num: headerData.value.count,
  350. // color: "#C280FF",
  351. // },
  352. // {
  353. // label: "客户数",
  354. // num: headerData.value.customerCount,
  355. // color: "#C280FF",
  356. // },
  357. // {
  358. // label: "订单金额",
  359. // num: proxy.moneyFormat(headerData.value.sumAmount, 2),
  360. // color: "#C280FF",
  361. // },
  362. // ],
  363. // },
  364. // {
  365. // label: "款项统计(CNY)",
  366. // type: 3,
  367. // data: [
  368. // {
  369. // label: "已收款",
  370. // num: proxy.moneyFormat(headerData.value.sumClaimMoney, 2),
  371. // color: "#FF9315",
  372. // },
  373. // {
  374. // label: "待收款",
  375. // num: proxy.moneyFormat(headerData.value.sumClaimMoneyOne, 2),
  376. // color: "#FF9315",
  377. // },
  378. // ],
  379. // },
  380. // ],
  381. // },
  382. ]);
  383. const config = computed(() => {
  384. return [
  385. {
  386. attrs: {
  387. label: "合同号",
  388. slot: "code",
  389. width: 140,
  390. },
  391. },
  392. {
  393. attrs: {
  394. label: "生产公司",
  395. prop: "companyName",
  396. width: 120,
  397. },
  398. },
  399. {
  400. attrs: {
  401. label: "销售部门",
  402. prop: "deptName",
  403. width: 120,
  404. },
  405. },
  406. {
  407. attrs: {
  408. label: "业务员",
  409. prop: "salesmanName",
  410. width: 100,
  411. },
  412. // render(type) {
  413. // return proxy.dictValueLabel(type, userList.value);
  414. // },
  415. },
  416. {
  417. attrs: {
  418. label: "下单时间",
  419. prop: "createTime",
  420. width: 160,
  421. },
  422. },
  423. {
  424. attrs: {
  425. label: "下发生产时间",
  426. prop: "orderDistributeTime",
  427. width: 160,
  428. },
  429. },
  430. {
  431. attrs: {
  432. label: "客户名称",
  433. slot: "buyCorporationName",
  434. "min-width": 180,
  435. },
  436. },
  437. {
  438. attrs: {
  439. label: "商品数据",
  440. slot: "product",
  441. "min-width": 240,
  442. },
  443. },
  444. // {
  445. // attrs: {
  446. // label: "客户标签",
  447. // slot: "tags",
  448. // width: 180,
  449. // },
  450. // },
  451. {
  452. attrs: {
  453. label: "是否已结清",
  454. slot: "isSettled",
  455. width: 100,
  456. },
  457. // render(type) {
  458. // return proxy.dictValueLabel(type, isSettled.value);
  459. // },
  460. },
  461. {
  462. attrs: {
  463. label: "预付比例",
  464. slot: "advanceRatio",
  465. width: 100,
  466. align: "right",
  467. },
  468. },
  469. {
  470. attrs: {
  471. label: "合同金额",
  472. slot: "amount",
  473. width: 140,
  474. align: "right",
  475. },
  476. },
  477. {
  478. attrs: {
  479. label: "汇率",
  480. prop: "rate",
  481. width: 80,
  482. align: "right",
  483. },
  484. render(rate) {
  485. return proxy.moneyFormat(rate, 4);
  486. },
  487. },
  488. // {
  489. // attrs: {
  490. // label: "合同金额(CNY)",
  491. // prop: "amountCNY",
  492. // width: 160,
  493. // align: "right",
  494. // },
  495. // render(amountCNY) {
  496. // return proxy.moneyFormat(amountCNY, 2);
  497. // },
  498. // },
  499. // {
  500. // attrs: {
  501. // label: "到账金额(CNY)",
  502. // prop: "sumClaimMoney",
  503. // width: 160,
  504. // align: "right",
  505. // },
  506. // render(sumClaimMoney) {
  507. // return proxy.moneyFormat(sumClaimMoney, 2);
  508. // },
  509. // },
  510. // {
  511. // attrs: {
  512. // label: "到账比例",
  513. // slot: "scale",
  514. // width: 100,
  515. // align: "right",
  516. // },
  517. // },
  518. {
  519. attrs: {
  520. label: "审批状态",
  521. prop: "status",
  522. width: 100,
  523. },
  524. render(type) {
  525. return proxy.dictValueLabel(type, status.value);
  526. },
  527. },
  528. {
  529. attrs: {
  530. label: "生产指示",
  531. slot: "prodTag",
  532. "min-width": 240,
  533. },
  534. },
  535. {
  536. attrs: {
  537. label: "操作",
  538. width: 200,
  539. align: "center",
  540. fixed: "right",
  541. },
  542. renderHTML(row) {
  543. return [
  544. // {
  545. // attrs: {
  546. // label: "交接单",
  547. // type: "primary",
  548. // text: true,
  549. // },
  550. // el: "button",
  551. // click() {
  552. // clickHandoverSlip(row);
  553. // },
  554. // },
  555. // row.status == 30
  556. // ? {
  557. // attrs: {
  558. // label: "变更",
  559. // type: "primary",
  560. // text: true,
  561. // },
  562. // el: "button",
  563. // click() {
  564. // clickAlteration(row);
  565. // },
  566. // }
  567. // : {},
  568. row.status == 30 && row.orderDistributeStatus != 1
  569. ? {
  570. attrs: {
  571. label: "下发生产",
  572. type: "primary",
  573. text: true,
  574. },
  575. el: "button",
  576. click() {
  577. clickDistributeProduction(row);
  578. },
  579. }
  580. : {},
  581. row.status == 30
  582. ? {
  583. attrs: {
  584. label: "打印",
  585. type: "primary",
  586. text: true,
  587. },
  588. el: "button",
  589. click() {
  590. clickPrint(row);
  591. },
  592. }
  593. : {},
  594. row.orderDistributeStatus == 1
  595. ? {}
  596. : {
  597. attrs: {
  598. label: "作废",
  599. type: "danger",
  600. text: true,
  601. },
  602. el: "button",
  603. click() {
  604. proxy
  605. .msgConfirm()
  606. .then((res) => {
  607. proxy
  608. .post("/contract/cancellation", {
  609. id: row.id,
  610. })
  611. .then((res) => {
  612. proxy.msgTip("操作成功", 1);
  613. getList();
  614. });
  615. })
  616. .catch((err) => {});
  617. },
  618. },
  619. row.status == 30
  620. ? {
  621. attrs: {
  622. label: "结清",
  623. type: "primary",
  624. text: true,
  625. },
  626. el: "button",
  627. click() {
  628. ElMessageBox.confirm("是否确认结清?", "提示", {
  629. confirmButtonText: "确定",
  630. cancelButtonText: "取消",
  631. type: "warning",
  632. }).then(() => {
  633. proxy
  634. .post("/contract/settle", {
  635. id: row.id,
  636. })
  637. .then(() => {
  638. ElMessage({
  639. message: "操作成功",
  640. type: "success",
  641. });
  642. getList();
  643. });
  644. });
  645. },
  646. }
  647. : {},
  648. // {
  649. // attrs: {
  650. // label: "生产指示",
  651. // type: "primary",
  652. // text: true,
  653. // },
  654. // el: "button",
  655. // click() {
  656. // handleEditTag(row);
  657. // },
  658. // },
  659. // {
  660. // attrs: {
  661. // label: "售后",
  662. // type: "primary",
  663. // text: true,
  664. // },
  665. // el: "button",
  666. // click() {
  667. // openRecords.value = true;
  668. // getRecordsData(row);
  669. // },
  670. // },
  671. ];
  672. },
  673. },
  674. ];
  675. });
  676. const getDict = () => {
  677. // proxy
  678. // .getDictOne([
  679. // "customer_tag",
  680. // "trade_mode",
  681. // "account_currency",
  682. // "shipping_method",
  683. // ])
  684. // .then((res) => {
  685. // customerTag.value = res["customer_tag"].map((x) => ({
  686. // label: x.dictValue,
  687. // value: x.dictKey,
  688. // }));
  689. // tradeMethods.value = res["trade_mode"].map((x) => ({
  690. // label: x.dictValue,
  691. // value: x.dictKey,
  692. // }));
  693. // accountCurrency.value = res["account_currency"].map((x) => ({
  694. // label: x.dictValue,
  695. // value: x.dictKey,
  696. // }));
  697. // shippingMethod.value = res["shipping_method"].map((x) => ({
  698. // label: x.dictValue,
  699. // value: x.dictKey,
  700. // }));
  701. // });
  702. // proxy.post("/corporation/page", { pageNum: 1, pageSize: 999 }).then((res) => {
  703. // corporationList.value = res.rows.map((item) => {
  704. // return {
  705. // ...item,
  706. // label: item.name,
  707. // value: item.id,
  708. // };
  709. // });
  710. // });
  711. proxy
  712. .get("/tenantDept/list", {
  713. pageNum: 1,
  714. pageSize: 9999,
  715. keyword: "",
  716. tenantId: proxy.useUserStore().user.tenantId,
  717. type: 0,
  718. })
  719. .then((res) => {
  720. companyData.value = res.data.map((x) => ({
  721. ...x,
  722. label: x.deptName,
  723. value: x.deptId,
  724. }));
  725. });
  726. proxy.post("/customer/page", { pageNum: 1, pageSize: 999 }).then((res) => {
  727. customerList.value = res.rows.map((item) => {
  728. return {
  729. ...item,
  730. label: item.name,
  731. value: item.id,
  732. };
  733. });
  734. });
  735. proxy
  736. .get("/tenantUser/list", {
  737. pageNum: 1,
  738. pageSize: 10000,
  739. tenantId: useUserStore().user.tenantId,
  740. })
  741. .then((res) => {
  742. userList.value = res.rows.map((item) => {
  743. return {
  744. label: item.nickName,
  745. value: item.userId,
  746. };
  747. });
  748. });
  749. };
  750. const getList = async (req) => {
  751. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  752. loading.value = true;
  753. proxy.post("/contract/page", sourceList.value.pagination).then((res) => {
  754. res.rows.forEach((x) => {
  755. // x.addTagShow = false;
  756. // if (x.tag) {
  757. // x.tags = x.tag.split(",");
  758. // } else {
  759. // x.tags = [];
  760. // }
  761. if (x.prodTag) {
  762. x.prodTags = x.prodTag.split(",");
  763. } else {
  764. x.prodTags = [];
  765. }
  766. });
  767. sourceList.value.data = res.rows;
  768. sourceList.value.pagination.total = res.total;
  769. setTimeout(() => {
  770. loading.value = false;
  771. }, 200);
  772. });
  773. // proxy
  774. // .post("/contract/getHeadStatistic", sourceList.value.pagination)
  775. // .then((res) => {
  776. // headerData.value = res;
  777. // if (headerData.value) {
  778. // headerData.value.sumClaimMoneyOne = parseFloat(
  779. // Number(headerData.value.sumAmount) -
  780. // Number(headerData.value.sumClaimMoney)
  781. // ).toFixed(2);
  782. // }
  783. // });
  784. };
  785. getDict();
  786. if (route.query.code) {
  787. sourceList.value.pagination.keyword = route.query.code;
  788. }
  789. getList();
  790. const newContract = () => {
  791. proxy.$router.replace({
  792. path: "/platform_manage/process/processApproval",
  793. query: {
  794. flowKey: "contract_flow",
  795. flowName: "销售合同审批流程",
  796. random: proxy.random(),
  797. },
  798. });
  799. };
  800. const openPrint = ref(false);
  801. const rowData = ref({});
  802. const clickPrint = (row) => {
  803. rowData.value = {
  804. id: row.id,
  805. };
  806. openPrint.value = true;
  807. };
  808. const clickDownload = () => {
  809. proxy.getPdf("外销合同PDF文件");
  810. };
  811. const openHandoverSlip = ref(false);
  812. const handoverSlipForm = ref({
  813. id: "",
  814. code: "",
  815. buyCorporationName: "",
  816. fileList: [],
  817. packageFileList: [],
  818. });
  819. const formOption = reactive({
  820. inline: true,
  821. labelWidth: 100,
  822. itemWidth: 100,
  823. rules: [],
  824. });
  825. const formConfig = computed(() => {
  826. return [
  827. {
  828. type: "input",
  829. prop: "code",
  830. label: "合同编号",
  831. itemType: "text",
  832. disabled: true,
  833. },
  834. {
  835. type: "input",
  836. prop: "buyCorporationName",
  837. label: "客户名称",
  838. itemType: "text",
  839. disabled: true,
  840. },
  841. {
  842. type: "slot",
  843. slotName: "file",
  844. label: "交接单",
  845. },
  846. {
  847. type: "slot",
  848. slotName: "indication",
  849. label: "包装指示",
  850. },
  851. ];
  852. });
  853. const uploadData = ref({});
  854. const indicationUploadData = ref({});
  855. const clickHandoverSlip = (item) => {
  856. handoverSlipForm.value.id = item.id;
  857. handoverSlipForm.value.code = item.code;
  858. handoverSlipForm.value.buyCorporationName = item.buyCorporationName;
  859. if (item.fileInfoVos && item.fileInfoVos.length > 0) {
  860. handoverSlipForm.value.fileList = item.fileInfoVos.map((item) => {
  861. return {
  862. raw: item,
  863. name: item.fileName,
  864. url: item.fileUrl,
  865. };
  866. });
  867. } else {
  868. handoverSlipForm.value.fileList = [];
  869. }
  870. if (item.packageFileInfoVOList && item.packageFileInfoVOList.length > 0) {
  871. handoverSlipForm.value.packageFileList = item.packageFileInfoVOList.map(
  872. (item) => {
  873. return {
  874. raw: item,
  875. name: item.fileName,
  876. url: item.fileUrl,
  877. };
  878. }
  879. );
  880. } else {
  881. handoverSlipForm.value.packageFileList = [];
  882. }
  883. openHandoverSlip.value = true;
  884. };
  885. const uploadFile = async (file) => {
  886. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  887. uploadData.value = res.uploadBody;
  888. file.id = res.id;
  889. file.fileName = res.fileName;
  890. file.fileUrl = res.fileUrl;
  891. file.uploadState = true;
  892. return true;
  893. };
  894. const indicationUploadFile = async (file) => {
  895. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  896. indicationUploadData.value = res.uploadBody;
  897. file.id = res.id;
  898. file.fileName = res.fileName;
  899. file.fileUrl = res.fileUrl;
  900. file.uploadState = true;
  901. return true;
  902. };
  903. const handleSuccess = (any, UploadFile) => {
  904. UploadFile.raw.uploadState = false;
  905. };
  906. const onPreviewFile = (file) => {
  907. window.open(file.raw.fileUrl, "_blank");
  908. };
  909. const submitHandoverSlip = () => {
  910. if (
  911. handoverSlipForm.value.fileList &&
  912. handoverSlipForm.value.fileList.length > 0
  913. ) {
  914. for (let i = 0; i < handoverSlipForm.value.fileList.length; i++) {
  915. if (handoverSlipForm.value.fileList[i].raw.uploadState) {
  916. return ElMessage("文件上传中,请稍后提交");
  917. }
  918. }
  919. }
  920. if (
  921. handoverSlipForm.value.packageFileList &&
  922. handoverSlipForm.value.packageFileList.length > 0
  923. ) {
  924. for (let i = 0; i < handoverSlipForm.value.packageFileList.length; i++) {
  925. if (handoverSlipForm.value.packageFileList[i].raw.uploadState) {
  926. return ElMessage("文件上传中,请稍后提交");
  927. }
  928. }
  929. }
  930. let data = proxy.deepClone(handoverSlipForm.value);
  931. if (data.fileList && data.fileList.length > 0) {
  932. data.fileList = data.fileList.map((item) => {
  933. return {
  934. id: item.raw.id,
  935. fileName: item.raw.fileName,
  936. fileUrl: item.raw.fileUrl,
  937. };
  938. });
  939. } else {
  940. data.fileList = [];
  941. }
  942. if (data.packageFileList && data.packageFileList.length > 0) {
  943. data.packageFileList = data.packageFileList.map((item) => {
  944. return {
  945. id: item.raw.id,
  946. fileName: item.raw.fileName,
  947. fileUrl: item.raw.fileUrl,
  948. };
  949. });
  950. } else {
  951. data.packageFileList = [];
  952. }
  953. proxy.post("/contract/contractHandover", data).then(() => {
  954. ElMessage({
  955. message: "操作成功!",
  956. type: "success",
  957. });
  958. openHandoverSlip.value = false;
  959. getList();
  960. });
  961. };
  962. const addTag = ref("");
  963. const judgeTagSelect = (data, val) => {
  964. if (data && data.length > 0) {
  965. if (data.includes(val)) {
  966. return true;
  967. }
  968. }
  969. return false;
  970. };
  971. const changeTag = (val, item) => {
  972. let data = {
  973. id: item.buyCorporationId,
  974. tag: proxy.deepClone(item.tags),
  975. };
  976. data.tag.push(val);
  977. data.tag = data.tag.join(",");
  978. proxy.post("/customer/editTag", data).then(() => {
  979. ElMessage({
  980. message: "添加成功",
  981. type: "success",
  982. });
  983. item.addTagShow = false;
  984. addTag.value = "";
  985. getList();
  986. });
  987. };
  988. const tagClose = (val, item) => {
  989. let data = {
  990. id: item.buyCorporationId,
  991. tag: proxy.deepClone(item.tags),
  992. };
  993. data.tag = data.tag.filter((row) => row !== val);
  994. if (data.tag && data.tag.length > 0) {
  995. data.tag = data.tag.join(",");
  996. } else {
  997. data.tag = "";
  998. }
  999. proxy.post("/customer/editTag", data).then(() => {
  1000. ElMessage({
  1001. message: "删除成功",
  1002. type: "success",
  1003. });
  1004. item.addTagShow = false;
  1005. addTag.value = "";
  1006. getList();
  1007. });
  1008. };
  1009. const showSelect = (item) => {
  1010. item.addTagShow = true;
  1011. };
  1012. const currentContractId = ref("");
  1013. const openDetails = (row) => {
  1014. // currentContractId.value = row.id;
  1015. // openDetailsDialog.value = true;
  1016. // 新页面打开方式
  1017. // const page = proxy.$router.resolve({
  1018. // name: "contractDetails",
  1019. // query: {
  1020. // currentContractId: row.id,
  1021. // },
  1022. // });
  1023. // window.open(page.href, "_blank");
  1024. proxy.$router.push({
  1025. name: "contractDetails",
  1026. query: {
  1027. currentContractId: row.id,
  1028. },
  1029. });
  1030. };
  1031. const computeScale = (item) => {
  1032. let text = 0;
  1033. if (
  1034. item.sumClaimMoney &&
  1035. Number(item.sumClaimMoney) > 0 &&
  1036. item.amountCNY &&
  1037. Number(item.amountCNY) > 0
  1038. ) {
  1039. text = parseFloat(
  1040. (Number(item.sumClaimMoney) / Number(item.amountCNY)) * 100
  1041. ).toFixed(2);
  1042. }
  1043. return text + "%";
  1044. };
  1045. const clickCorporationName = (row) => {
  1046. proxy.$router.push({
  1047. name: "Portrait",
  1048. query: {
  1049. id: row.buyCorporationId,
  1050. },
  1051. });
  1052. };
  1053. const printObj = ref({
  1054. id: "pdfDom",
  1055. popTitle: "",
  1056. extraCss:
  1057. "https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.compat.css, https://cdn.bootcdn.net/ajax/libs/hover.css/2.3.1/css/hover-min.css",
  1058. extraHead: '<meta http-equiv="Content-Language"content="zh-cn"/>',
  1059. });
  1060. const clickAlteration = (row) => {
  1061. proxy.$router.push({
  1062. path: "/platform_manage/process/processApproval",
  1063. query: {
  1064. flowKey: "contract_update_flow",
  1065. flowName: "销售合同变更流程",
  1066. random: proxy.random(),
  1067. businessId: row.id,
  1068. },
  1069. });
  1070. };
  1071. const PdfDom = ref(null);
  1072. const exportExcel = () => {
  1073. PdfDom.value.exportExcel();
  1074. };
  1075. const formData = reactive({
  1076. recordsFormData: {},
  1077. data: {},
  1078. tagData: {},
  1079. });
  1080. const formLoading = ref(false);
  1081. const openRecords = ref(false);
  1082. const openAddRecords = ref(false);
  1083. const recordsLoading = ref(false);
  1084. const recordsData = ref([]);
  1085. const recordsForm = ref(null);
  1086. const rowContractData = ref({});
  1087. const recordsFormConfig = computed(() => [
  1088. {
  1089. type: "date",
  1090. itemType: "datetime",
  1091. prop: "documentaryTime",
  1092. label: "售后时间",
  1093. disabled: false,
  1094. },
  1095. {
  1096. type: "input",
  1097. prop: "documentaryRemark",
  1098. label: "售后记录",
  1099. itemType: "textarea",
  1100. disabled: false,
  1101. },
  1102. {
  1103. type: "slot",
  1104. slotName: "file",
  1105. label: "上传附件",
  1106. },
  1107. ]);
  1108. const recordsRules = ref({
  1109. documentaryTime: [
  1110. { required: true, message: "请选择售后时间", trigger: "change" },
  1111. ],
  1112. documentaryRemark: [
  1113. { required: true, message: "请输入售后记录", trigger: "blur" },
  1114. ],
  1115. });
  1116. const getRecordsData = (row) => {
  1117. if (row && row.id) {
  1118. rowContractData.value = row;
  1119. }
  1120. proxy
  1121. .post("/contractDocumentary/page", {
  1122. businessId: rowContractData.value.id,
  1123. documentaryType: "-2",
  1124. })
  1125. .then((res) => {
  1126. recordsData.value = res.rows;
  1127. const idList = recordsData.value.map((x) => x.id);
  1128. // 请求文件数据并回显
  1129. if (idList.length > 0) {
  1130. proxy
  1131. .post("/fileInfo/getList", {
  1132. businessIdList: idList,
  1133. })
  1134. .then((fileObj) => {
  1135. if (fileObj) {
  1136. for (let i = 0; i < recordsData.value.length; i++) {
  1137. const e = recordsData.value[i];
  1138. for (const key in fileObj) {
  1139. if (e.id === key) {
  1140. e.fileList = fileObj[key];
  1141. }
  1142. }
  1143. }
  1144. }
  1145. });
  1146. }
  1147. });
  1148. };
  1149. const handleClickAddRecord = () => {
  1150. formData.recordsFormData = {
  1151. businessId: rowContractData.value.id,
  1152. businessType: "0",
  1153. documentaryType: "-2",
  1154. documentaryTime: proxy.parseTime(new Date()),
  1155. documentaryRemark: "",
  1156. fileList: [],
  1157. };
  1158. openAddRecords.value = true;
  1159. };
  1160. const submitRecords = () => {
  1161. recordsForm.value.handleSubmit(() => {
  1162. formLoading.value = true;
  1163. formData.recordsFormData.fileList = formData.recordsFormData.fileList.map(
  1164. (item) => {
  1165. return {
  1166. id: item.raw.id,
  1167. fileName: item.raw.fileName,
  1168. fileUrl: item.raw.fileUrl,
  1169. uploadState: item.raw.uploadState,
  1170. };
  1171. }
  1172. );
  1173. proxy
  1174. .post("/contractDocumentary/add", formData.recordsFormData)
  1175. .then((res) => {
  1176. ElMessage({
  1177. message: "操作成功",
  1178. type: "success",
  1179. });
  1180. formLoading.value = false;
  1181. openAddRecords.value = false;
  1182. getRecordsData();
  1183. });
  1184. });
  1185. };
  1186. const openFile = (item) => {
  1187. window.open(item.fileUrl, "_blank");
  1188. };
  1189. const formSearchConfig = computed(() => {
  1190. return [
  1191. {
  1192. type: "select",
  1193. label: "审批状态",
  1194. prop: "status",
  1195. itemWidth: 50,
  1196. data: status.value,
  1197. clearable: true,
  1198. },
  1199. {
  1200. type: "select",
  1201. label: "生产公司",
  1202. prop: "companyId",
  1203. itemWidth: 50,
  1204. data: companyData.value,
  1205. clearable: true,
  1206. },
  1207. {
  1208. type: "select",
  1209. label: "业务员",
  1210. prop: "userId",
  1211. data: userList.value,
  1212. clearable: true,
  1213. },
  1214. {
  1215. type: "date",
  1216. itemType: "datetime",
  1217. label: "合同时间",
  1218. prop: "beginTime",
  1219. placeholder: "合同开始时间",
  1220. itemWidth: 50,
  1221. clearable: true,
  1222. },
  1223. {
  1224. type: "date",
  1225. itemType: "datetime",
  1226. label: " ",
  1227. prop: "endTime",
  1228. placeholder: "合同结束时间",
  1229. itemWidth: 50,
  1230. clearable: true,
  1231. },
  1232. ];
  1233. });
  1234. const moreSearchDialog = ref(false);
  1235. const clickMoreSearch = () => {
  1236. moreSearchDialog.value = true;
  1237. };
  1238. const moreSearchQuery = () => {
  1239. moreSearchDialog.value = false;
  1240. getList();
  1241. };
  1242. const moreSearchReset = () => {
  1243. sourceList.value.pagination = {
  1244. total: 0,
  1245. pageNum: sourceList.value.pagination.pageNum,
  1246. pageSize: sourceList.value.pagination.pageSize,
  1247. keyword: "",
  1248. status: "",
  1249. sellCorporationId: "",
  1250. beginTime: "",
  1251. endTime: "",
  1252. };
  1253. moreSearchQuery();
  1254. };
  1255. const productionFormDom = ref(null);
  1256. const productionDialog = ref(false);
  1257. const productionFormConfig = computed(() => [
  1258. // {
  1259. // type: "slot",
  1260. // slotName: "companyName",
  1261. // label: "报价子公司:",
  1262. // prop: "companyName",
  1263. // itemWidth: 100,
  1264. // isShow: formData.data.companyName ? true : false,
  1265. // },
  1266. {
  1267. type: "treeSelect",
  1268. prop: "produceCompanyId",
  1269. label: "生产公司",
  1270. data: companyData.value,
  1271. propsTreeLabel: "deptName",
  1272. propsTreeValue: "deptId",
  1273. itemWidth: 100,
  1274. disabled: true,
  1275. },
  1276. {
  1277. type: "date",
  1278. itemType: "datetime",
  1279. label: "交期",
  1280. prop: "deliveryPeriod",
  1281. // placeholder: "合同开始时间",
  1282. itemWidth: 100,
  1283. clearable: true,
  1284. },
  1285. ]);
  1286. const productionRules = ref({
  1287. produceCompanyId: [
  1288. { required: true, message: "请选择生产公司", trigger: "change" },
  1289. ],
  1290. deliveryPeriod: [
  1291. { required: true, message: "请选择交期", trigger: "change" },
  1292. ],
  1293. });
  1294. const clickDistributeProduction = (row) => {
  1295. formData.data = {
  1296. contractId: row.id,
  1297. deliveryPeriod: "",
  1298. produceCompanyId: row.companyId,
  1299. companyName: row.quotationId ? row.companyName : "",
  1300. };
  1301. productionDialog.value = true;
  1302. };
  1303. const submitProduction = () => {
  1304. productionFormDom.value.handleSubmit(() => {
  1305. formLoading.value = true;
  1306. proxy.post("/produceOrder/createOrder", formData.data).then((res) => {
  1307. proxy.msgTip("操作成功");
  1308. formLoading.value = false;
  1309. productionDialog.value = false;
  1310. getList();
  1311. });
  1312. });
  1313. };
  1314. const handleEditTag = (row) => {
  1315. formData.tagData = {
  1316. id: row.id,
  1317. prodTag: row.prodTags,
  1318. };
  1319. tagDialog.value = true;
  1320. };
  1321. const tagFormDom = ref(null);
  1322. const tagDialog = ref(false);
  1323. const tagFormConfig = computed(() => [
  1324. {
  1325. type: "select",
  1326. prop: "prodTag",
  1327. label: "生产指示",
  1328. multiple: true,
  1329. data: contractTag.value,
  1330. itemWidth: 100,
  1331. },
  1332. ]);
  1333. const tagRules = ref({
  1334. prodTag: [{ required: true, message: "请选择生产指示", trigger: "change" }],
  1335. });
  1336. const submitTag = () => {
  1337. tagFormDom.value.handleSubmit(() => {
  1338. const data = {
  1339. id: formData.tagData.id,
  1340. prodTag: formData.tagData.prodTag.join(","),
  1341. };
  1342. formLoading.value = true;
  1343. proxy.post("/contract/updateProductionTag", data).then((res) => {
  1344. proxy.msgTip("操作成功");
  1345. formLoading.value = false;
  1346. tagDialog.value = false;
  1347. getList();
  1348. });
  1349. });
  1350. };
  1351. const prodTagClose = (index, row) => {
  1352. row.prodTags.splice(index, 1);
  1353. proxy
  1354. .post("/contract/updateProductionTag", {
  1355. id: row.id,
  1356. prodTag: row.prodTags.join(","),
  1357. })
  1358. .then((res) => {});
  1359. };
  1360. const handleClickFile = (fileUrl) => {
  1361. window.open(fileUrl, "_blank");
  1362. };
  1363. const productData = ref([]);
  1364. const onShowProductData = (item) => {
  1365. productData.value = item.contractProductList;
  1366. };
  1367. onMounted(() => {
  1368. $bus.on("refreshTableData", () => {
  1369. getList();
  1370. });
  1371. });
  1372. onBeforeUnmount(() => {
  1373. // 取消订阅特定事件
  1374. $bus.off("refreshTableData");
  1375. });
  1376. </script>
  1377. <style lang="scss" scoped>
  1378. .tenant {
  1379. padding: 20px;
  1380. }
  1381. ::v-deep(.el-input-number .el-input__inner) {
  1382. text-align: left;
  1383. }
  1384. .baseRow {
  1385. min-height: 24px;
  1386. border-top: 1px solid black;
  1387. border-left: 1px solid black;
  1388. }
  1389. .contentRow {
  1390. border-right: 1px solid black;
  1391. line-height: 24px;
  1392. padding-left: 4px;
  1393. }
  1394. .active {
  1395. background: #a6dd82;
  1396. color: #fff;
  1397. border-radius: 4px;
  1398. }
  1399. </style>