index.vue 36 KB

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