index.vue 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  1. <template>
  2. <div class="tenant">
  3. <byTable :hideTable="true" :hidePagination="true" :source="sourceList.data" :pagination="sourceList.pagination" :config="config"
  4. :statConfig="statConfig" :selectConfig="selectConfig" highlight-current-row :onMoreSearch="true" @moreSearch="clickMoreSearch"
  5. :action-list="[
  6. {
  7. text: '默认汇率',
  8. action: () => openModal(),
  9. },
  10. ]" @get-list="getList">
  11. </byTable>
  12. <div style="padding: 0 20px 0px 20px; background-color: white" v-if="rateStatus">
  13. <el-table :data="sourceList.data" v-loading="loading" :height="tableHeight">
  14. <el-table-column label="合同编号" prop="code" width="140" fixed />
  15. <el-table-column label="合同金额" width="140" fixed>
  16. <template #default="{ row }">
  17. <div>{{ row.currency }} {{ moneyFormat( row.amount,2) }}</div>
  18. </template>
  19. </el-table-column>
  20. <!-- <el-table-column label="是否已结清" width="120" fixed>
  21. <template #default="{ row }">
  22. <div> {{ dictValueLabel(row.isSettled, isSettled) }}</div>
  23. </template>
  24. </el-table-column> -->
  25. <el-table-column label="是否已结清" width="100" fixed>
  26. <template #default="{ row }">
  27. <div>
  28. <span style="padding: 4px" :class="[row.isSettled == 1 ? 'active' : '']">
  29. {{
  30. proxy.dictValueLabel(row.isSettled, isSettled)
  31. }}</span>
  32. </div>
  33. </template>
  34. </el-table-column>
  35. <el-table-column label="收入总计(CNY)" prop="incomeAmount" width="100" fixed>
  36. <template #default="{ row }">
  37. <div> {{ moneyFormat(row.incomeAmount ,2) }}</div>
  38. </template>
  39. </el-table-column>
  40. <el-table-column label="支出总计(CNY)" prop="expenditureAmount" width="100" fixed>
  41. <template #default="{ row }">
  42. <div> {{ moneyFormat(row.expenditureAmount,2) }}</div>
  43. </template>
  44. </el-table-column>
  45. <el-table-column label="毛利" prop="gross" width="130" fixed>
  46. <template #default="{ row,$index }">
  47. <div style="display:flex">
  48. <el-popover placement="top-start" :width="600" trigger="hover" @show="showEcharts(row,$index)">
  49. <template #default>
  50. <div>
  51. <div :ref="row.contractId+$index" style="height:320px">
  52. </div>
  53. </div>
  54. </template>
  55. <template #reference>
  56. <div style="margin-right:8px;cursor:pointer;position:relative;top:-3px">
  57. <img src="@/assets/images/tubiao-zhexiantu.png" alt="" class="pic">
  58. </div>
  59. </template>
  60. </el-popover>
  61. <div>{{ moneyFormat(row.gross ,2)}}</div>
  62. </div>
  63. </template>
  64. </el-table-column>
  65. <el-table-column label="毛利率" width="80" fixed>
  66. <template #default="{ row }">
  67. <div>{{ parseFloat(row.grossRate).toFixed(2) }}%</div>
  68. </template>
  69. </el-table-column>
  70. <el-table-column label="客户名称" prop="customerName" min-width="200" />
  71. <el-table-column label="业务员" prop="userName" width="120" />
  72. <el-table-column label="应付货款" width="120">
  73. <template #default="{ row }">
  74. <div>
  75. <span v-if="row.otherSumAmount">{{moneyFormat( row.otherSumAmount,2) }}</span>
  76. <span v-else>{{ moneyFormat(row.ehsdSumAmount,2) }}</span>
  77. </div>
  78. </template>
  79. </el-table-column>
  80. <el-table-column label="税率" width="120">
  81. <template #default="{ row }">
  82. <div>13%</div>
  83. </template>
  84. </el-table-column>
  85. <el-table-column label="应退税金额" prop="refundableAmount" width="120">
  86. <template #default="{ row }">
  87. <div>{{ moneyFormat(row.refundableAmount ,2)}}</div>
  88. </template>
  89. </el-table-column>
  90. <el-table-column label="包材金额" width="120">
  91. <template #default="{ row }">
  92. <div>{{ moneyFormat(row.peritectoidAmount,2) }}</div>
  93. </template>
  94. </el-table-column>
  95. <el-table-column label="配件金额" width="120">
  96. <template #default="{ row }">
  97. <div>{{ moneyFormat(row.accessoriesAmount,2) }}</div>
  98. </template>
  99. </el-table-column>
  100. <el-table-column label="拖车费" width="120">
  101. <template #default="{ row }">
  102. <div>{{ moneyFormat(row.trailerFee,2) }}</div>
  103. </template>
  104. </el-table-column>
  105. <el-table-column label="报关费" width="120">
  106. <template #default="{ row }">
  107. <div>{{ moneyFormat(row.customsFee,2) }}</div>
  108. </template>
  109. </el-table-column>
  110. <el-table-column label="代理费" width="120">
  111. <template #default="{ row }">
  112. <div>{{ moneyFormat(row.agencyFee,2) }}</div>
  113. </template>
  114. </el-table-column>
  115. <el-table-column label="港杂费" width="120">
  116. <template #default="{ row }">
  117. <div>{{moneyFormat( row.portMixedFee,2) }}</div>
  118. </template>
  119. </el-table-column>
  120. <el-table-column label="验货红包" width="120">
  121. <template #default="{ row }">
  122. <div>
  123. {{ moneyFormat(row.inspectionRedPack ,2)}}
  124. </div>
  125. </template>
  126. </el-table-column>
  127. <el-table-column label="佣金" width="120">
  128. <template #default="{ row }">
  129. <div>{{ moneyFormat(row.commission,2) }}</div>
  130. </template>
  131. </el-table-column>
  132. <el-table-column label="其他" width="120">
  133. <template #default="{ row }">
  134. <div>{{ moneyFormat(row.other ,2)}}</div>
  135. </template>
  136. </el-table-column>
  137. <el-table-column label="操作" align="center" width="110" fixed="right">
  138. <template #default="{ row }">
  139. <div>
  140. <el-button type="primary" @click="changeExchangeRate(row)" link>汇率</el-button>
  141. <el-button type="primary" @click="changeBudget(row)" link>预算</el-button>
  142. </div>
  143. </template>
  144. </el-table-column>
  145. </el-table>
  146. <el-row style="padding: 20px" justify="end" type="flex">
  147. <el-pagination background layout="total, sizes, prev, pager, next, jumper" :current-page="sourceList.pagination.pageNum"
  148. :page-size="sourceList.pagination.pageSize" :total="sourceList.pagination.total" @size-change="handleSizeChange"
  149. @current-change="handlePageChange" />
  150. </el-row>
  151. </div>
  152. <el-dialog title="默认汇率" v-if="dialogVisible" v-model="dialogVisible" width="600">
  153. <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="submit">
  154. <template #currencyList>
  155. <el-table :data="formData.data.list" style="width: 100%" v-loading="loadingDialog">
  156. <el-table-column label="币种">
  157. <template #default="{ row }">
  158. <div>{{ dictValueLabel(row.type, accountCurrency) }}</div>
  159. </template>
  160. </el-table-column>
  161. <el-table-column label="兑 CHY 汇率">
  162. <template #default="{ row, $index }">
  163. <el-form-item :prop="'list.' + $index + '.rate'" :rules="rules.rate" :inline-message="true">
  164. <el-input-number onmousewheel="return false;" v-model="row.rate" placeholder="请输入兑 CHY 汇率" style="width: 100%" :precision="6"
  165. :controls="false" :min="0" />
  166. </el-form-item>
  167. </template>
  168. </el-table-column>
  169. </el-table>
  170. </template>
  171. </byForm>
  172. <template #footer>
  173. <el-button @click="dialogVisible = false" size="large">取 消</el-button>
  174. <el-button type="primary" @click="submitForm()" size="large">确 定</el-button>
  175. </template>
  176. </el-dialog>
  177. <el-dialog title="调整汇率" v-if="openChange" v-model="openChange" width="600">
  178. <byForm :formConfig="formChangeConfig" :formOption="formOption" v-model="formChangeData.data" :rules="rules" ref="change">
  179. <template #currencyList>
  180. <el-table :data="formChangeData.data.list" style="width: 100%" v-loading="loadingDialog">
  181. <el-table-column label="币种">
  182. <template #default="{ row }">
  183. <div>{{ dictValueLabel(row.type, accountCurrency) }}</div>
  184. </template>
  185. </el-table-column>
  186. <el-table-column label="兑 CHY 汇率">
  187. <template #default="{ row, $index }">
  188. <el-form-item :prop="'list.' + $index + '.rate'" :rules="rules.rate" :inline-message="true">
  189. <el-input-number onmousewheel="return false;" v-model="row.rate" placeholder="请输入兑 CHY 汇率" style="width: 100%" :precision="6"
  190. :controls="false" :min="0" />
  191. </el-form-item>
  192. </template>
  193. </el-table-column>
  194. </el-table>
  195. </template>
  196. </byForm>
  197. <template #footer>
  198. <el-button @click="openChange = false" size="large">取 消</el-button>
  199. <el-button type="primary" @click="submitChangeForm()" size="large">确 定</el-button>
  200. </template>
  201. </el-dialog>
  202. <el-dialog title="预算" v-if="openBudget" v-model="openBudget" width="400">
  203. <byForm :formConfig="formBudgetConfig" :formOption="formOption" v-model="formBudgetData.data" ref="budget">
  204. <template #budgetMoney>
  205. <div style="width: 100%">
  206. <el-form-item label="拖车费" prop="trailerFee">
  207. <el-input v-model="formBudgetData.data.trailerFee" placeholder="请输入拖车费" class="input-with-select">
  208. <template #prepend>
  209. <el-select v-model="formBudgetData.data.trailerFeeCurrency" placeholder="请选择货币" style="width: 115px" disabled>
  210. <el-option v-for="(item, index) in accountCurrency" :key="index" :label="item.label" :value="item.value" />
  211. </el-select>
  212. </template>
  213. </el-input>
  214. </el-form-item>
  215. <el-form-item label="报关费" prop="customsFee" style="margin-top: 20px">
  216. <el-input v-model="formBudgetData.data.customsFee" placeholder="请输入报关费" class="input-with-select">
  217. <template #prepend>
  218. <el-select v-model="formBudgetData.data.customsFeeCurrency" placeholder="请选择货币" style="width: 115px" disabled>
  219. <el-option v-for="(item, index) in accountCurrency" :key="index" :label="item.label" :value="item.value" />
  220. </el-select>
  221. </template>
  222. </el-input>
  223. </el-form-item>
  224. <el-form-item label="代理费" prop="agencyFee" style="margin-top: 20px">
  225. <el-input v-model="formBudgetData.data.agencyFee" placeholder="请输入代理费" class="input-with-select">
  226. <template #prepend>
  227. <el-select v-model="formBudgetData.data.agencyFeeCurrency" placeholder="请选择货币" style="width: 115px" disabled>
  228. <el-option v-for="(item, index) in accountCurrency" :key="index" :label="item.label" :value="item.value" />
  229. </el-select>
  230. </template>
  231. </el-input>
  232. </el-form-item>
  233. <el-form-item label="港杂费" prop="portMixedFee" style="margin-top: 20px">
  234. <el-input v-model="formBudgetData.data.portMixedFee" placeholder="请输入港杂费" class="input-with-select">
  235. <template #prepend>
  236. <el-select v-model="formBudgetData.data.portMixedFeeCurrency" placeholder="请选择货币" style="width: 115px" disabled>
  237. <el-option v-for="(item, index) in accountCurrency" :key="index" :label="item.label" :value="item.value" />
  238. </el-select>
  239. </template>
  240. </el-input>
  241. </el-form-item>
  242. <el-form-item label="验货红包" prop="inspectionRedPack" style="margin-top: 20px">
  243. <el-input v-model="formBudgetData.data.inspectionRedPack" placeholder="请输入验货红包" class="input-with-select">
  244. <template #prepend>
  245. <el-select v-model="formBudgetData.data.inspectionRedPackCurrency" placeholder="请选择货币" style="width: 115px" disabled>
  246. <el-option v-for="(item, index) in accountCurrency" :key="index" :label="item.label" :value="item.value" />
  247. </el-select>
  248. </template>
  249. </el-input>
  250. </el-form-item>
  251. <el-form-item label="佣金" prop="commission" style="margin-top: 20px">
  252. <el-input v-model="formBudgetData.data.commission" placeholder="请输入佣金" class="input-with-select">
  253. <template #prepend>
  254. <el-select v-model="formBudgetData.data.commissionCurrency" placeholder="请选择货币" style="width: 115px" disabled>
  255. <el-option v-for="(item, index) in accountCurrency" :key="index" :label="item.label" :value="item.value" />
  256. </el-select>
  257. </template>
  258. </el-input>
  259. </el-form-item>
  260. <el-form-item label="其他" prop="other" style="margin-top: 20px">
  261. <el-input v-model="formBudgetData.data.other" placeholder="请输入其他" class="input-with-select">
  262. <template #prepend>
  263. <el-select v-model="formBudgetData.data.otherCurrency" placeholder="请选择货币" style="width: 115px" disabled>
  264. <el-option v-for="(item, index) in accountCurrency" :key="index" :label="item.label" :value="item.value" />
  265. </el-select>
  266. </template>
  267. </el-input>
  268. </el-form-item>
  269. </div>
  270. </template>
  271. </byForm>
  272. <template #footer>
  273. <el-button @click="openBudget = false" size="large">取 消</el-button>
  274. <el-button type="primary" @click="submitBudgetForm()" size="large">确 定</el-button>
  275. </template>
  276. </el-dialog>
  277. <el-dialog :title="'高级检索'" v-model="moreSearchDialog" width="500px" destroy-on-close>
  278. <byForm :formConfig="formSearchConfig" :formOption="formOption" v-model="sourceList.pagination">
  279. </byForm>
  280. <template #footer>
  281. <el-button @click="moreSearchReset" size="large">重置</el-button>
  282. <el-button @click="moreSearchQuery" type="primary" size="large">搜索</el-button>
  283. </template>
  284. </el-dialog>
  285. </div>
  286. </template>
  287. <script setup>
  288. import { computed, ref } from "vue";
  289. import byTable from "@/components/byTable/index";
  290. import byForm from "@/components/byForm/index";
  291. import useUserStore from "@/store/modules/user";
  292. import { ElMessage } from "element-plus";
  293. import * as echarts from "echarts";
  294. const tableHeight = ref(0);
  295. const getTableHeight = () => {
  296. if (window.innerHeight >= 920) {
  297. tableHeight.value = 650;
  298. } else {
  299. tableHeight.value = 550;
  300. }
  301. };
  302. getTableHeight();
  303. window.addEventListener("resize", () => {
  304. getTableHeight();
  305. });
  306. const { proxy } = getCurrentInstance();
  307. const accountCurrency = ref([]);
  308. const userList = ref([]);
  309. const sourceList = ref({
  310. data: [],
  311. pagination: {
  312. total: 0,
  313. pageNum: 1,
  314. pageSize: 10,
  315. keyword: "",
  316. userId: "",
  317. userName: "",
  318. contractCode: "",
  319. customerName: "",
  320. beginTime: "",
  321. endTime: "",
  322. },
  323. });
  324. const loading = ref(false);
  325. const isSettled = ref([
  326. {
  327. label: "已结清",
  328. value: "1",
  329. },
  330. {
  331. label: "未结清",
  332. value: "0",
  333. },
  334. ]);
  335. const selectConfig = computed(() => {
  336. return [
  337. {
  338. label: "业务员",
  339. prop: "userId",
  340. data: userList.value,
  341. },
  342. {
  343. label: "是否已结清",
  344. prop: "isSettled",
  345. data: isSettled.value,
  346. },
  347. ];
  348. });
  349. const config = computed(() => {
  350. return [];
  351. });
  352. const headerData = ref({});
  353. const statConfig = computed(() => [
  354. {
  355. label: "统计",
  356. data: [
  357. //一个卡牌多数据配置
  358. {
  359. label: "订单统计(CNY)",
  360. type: 2,
  361. data: [
  362. {
  363. label: "销售总金额",
  364. num: proxy.moneyFormat(headerData.value.contractSumAmount, 2),
  365. color: "#C280FF",
  366. },
  367. {
  368. label: "采购总金额",
  369. num: proxy.moneyFormat(headerData.value.purchaseSumAmount, 2),
  370. color: "#C280FF",
  371. },
  372. ],
  373. },
  374. {
  375. label: "收入统计(CNY)",
  376. type: 3,
  377. data: [
  378. {
  379. label: "应退税",
  380. num: proxy.moneyFormat(headerData.value.taxReturnMoneySumAmount, 2),
  381. color: "#FF9315",
  382. },
  383. ],
  384. },
  385. {
  386. label: "支出统计(CNY)",
  387. type: 5,
  388. data: [
  389. {
  390. label: "包材金额",
  391. num: proxy.moneyFormat(headerData.value.peritectoidSumAmount, 2),
  392. color: "#FF6F67",
  393. },
  394. {
  395. label: "配件金额",
  396. num: proxy.moneyFormat(headerData.value.accessoriesSumAmount, 2),
  397. color: "#FF6F67",
  398. },
  399. {
  400. label: "拖车费",
  401. num: proxy.moneyFormat(headerData.value.trailerFeeSumAmount, 2),
  402. color: "#FF6F67",
  403. },
  404. {
  405. label: "报关费",
  406. num: proxy.moneyFormat(headerData.value.customsFeeSumAmount, 2),
  407. color: "#FF6F67",
  408. },
  409. {
  410. label: "代理费",
  411. num: proxy.moneyFormat(headerData.value.agencyFeeSumAmount, 2),
  412. color: "#FF6F67",
  413. },
  414. {
  415. label: "港杂费",
  416. num: proxy.moneyFormat(headerData.value.portMixedFeeSumAmount, 2),
  417. color: "#FF6F67",
  418. },
  419. {
  420. label: "验货红包",
  421. num: proxy.moneyFormat(
  422. headerData.value.inspectionRedPackSumAmount,
  423. 2
  424. ),
  425. color: "#FF6F67",
  426. },
  427. {
  428. label: "佣金",
  429. num: proxy.moneyFormat(headerData.value.commissionSumAmount, 2),
  430. color: "#FF6F67",
  431. },
  432. {
  433. label: "其他",
  434. num: proxy.moneyFormat(headerData.value.otherSumAmount, 2),
  435. color: "#FF6F67",
  436. },
  437. ],
  438. },
  439. {
  440. label: "收支统计(CNY)",
  441. type: 1,
  442. data: [
  443. {
  444. label: "总收入",
  445. num: proxy.moneyFormat(headerData.value.totalIncomeSumAmount, 2),
  446. color: "#0084ff",
  447. },
  448. {
  449. label: "总支出",
  450. num: proxy.moneyFormat(headerData.value.totalExpensesSumAmount, 2),
  451. color: "#0084ff",
  452. },
  453. {
  454. label: "总毛利",
  455. num: proxy.moneyFormat(headerData.value.grossProfitSum, 2),
  456. color: "#0084ff",
  457. },
  458. {
  459. label: "毛利率",
  460. num: headerData.value.grossProfitMargin + " %",
  461. color: "#0084ff",
  462. },
  463. ],
  464. },
  465. ],
  466. },
  467. ]);
  468. const getDict = () => {
  469. proxy
  470. .post("/dictTenantData/page", {
  471. pageNum: 1,
  472. pageSize: 999,
  473. dictCode: "account_currency",
  474. tenantId: useUserStore().user.tenantId,
  475. })
  476. .then((res) => {
  477. if (res.rows && res.rows.length > 0) {
  478. accountCurrency.value = res.rows.map((item) => {
  479. return {
  480. label: item.dictValue,
  481. value: item.dictKey,
  482. };
  483. });
  484. judgeRate();
  485. } else {
  486. ElMessage("请先添加货币");
  487. }
  488. });
  489. proxy
  490. .get("/tenantUser/list", {
  491. pageNum: 1,
  492. pageSize: 10000,
  493. tenantId: useUserStore().user.tenantId,
  494. })
  495. .then((res) => {
  496. userList.value = res.rows.map((item) => {
  497. return {
  498. label: item.nickName,
  499. value: item.userId,
  500. };
  501. });
  502. });
  503. };
  504. const getList = async (req) => {
  505. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  506. loading.value = true;
  507. proxy
  508. .post("/contract/getProfitBudgetPage", sourceList.value.pagination)
  509. .then((res) => {
  510. sourceList.value.data = res.rows;
  511. sourceList.value.pagination.total = res.total;
  512. setTimeout(() => {
  513. loading.value = false;
  514. }, 200);
  515. });
  516. proxy
  517. .post("/contract/getProfitBudgetHeadStatistic", sourceList.value.pagination)
  518. .then((res) => {
  519. headerData.value = res;
  520. });
  521. };
  522. const rateStatus = ref(false);
  523. const judgeRate = () => {
  524. proxy.post("/currencyRate/list", {}).then(
  525. (res) => {
  526. if (res && res.length > 0) {
  527. for (let i = 0; i < accountCurrency.value.length; i++) {
  528. let currencyStatus = true;
  529. for (let j = 0; j < res.length; j++) {
  530. if (accountCurrency.value[i].value === res[j].type) {
  531. currencyStatus = false;
  532. break;
  533. }
  534. }
  535. if (currencyStatus) {
  536. return ElMessage("请先完成默认汇率的配置");
  537. }
  538. }
  539. rateStatus.value = true;
  540. getList();
  541. } else {
  542. ElMessage("请先完成默认汇率的配置");
  543. }
  544. },
  545. (err) => {
  546. console.log(err);
  547. ElMessage("请先完成默认汇率的配置");
  548. }
  549. );
  550. };
  551. getDict();
  552. const handleSizeChange = (val) => {
  553. sourceList.value.pagination.pageNum = 1;
  554. sourceList.value.pagination.pageSize = val;
  555. getList();
  556. };
  557. const handlePageChange = (val) => {
  558. sourceList.value.pagination.pageNum = val;
  559. getList();
  560. };
  561. const dialogVisible = ref(false);
  562. const loadingDialog = ref(false);
  563. const submit = ref(null);
  564. const formOption = reactive({
  565. inline: true,
  566. labelWidth: 100,
  567. itemWidth: 100,
  568. rules: [],
  569. });
  570. const formData = reactive({
  571. data: {
  572. list: [],
  573. },
  574. });
  575. const formConfig = computed(() => {
  576. return [
  577. {
  578. type: "slot",
  579. prop: "currencyList",
  580. slotName: "currencyList",
  581. label: "",
  582. },
  583. ];
  584. });
  585. const rules = ref({
  586. rate: [{ required: true, message: "请输入兑 CHY 汇率", trigger: "blur" }],
  587. });
  588. const openModal = () => {
  589. if (accountCurrency.value && accountCurrency.value.length > 0) {
  590. formData.data = {
  591. list: accountCurrency.value.map((item) => {
  592. return {
  593. id: "",
  594. type: item.value,
  595. rate: 1,
  596. };
  597. }),
  598. };
  599. } else {
  600. formData.data = {
  601. list: [],
  602. };
  603. }
  604. loadingDialog.value = true;
  605. dialogVisible.value = true;
  606. proxy.post("/currencyRate/list", {}).then(
  607. (res) => {
  608. if (res && res.length > 0 && formData.data.list.length > 0) {
  609. formData.data.list = formData.data.list.map((item) => {
  610. for (let i = 0; i < res.length; i++) {
  611. if (item.type === res[i].type) {
  612. item.id = res[i].id;
  613. item.rate = res[i].rate;
  614. break;
  615. }
  616. }
  617. return {
  618. ...item,
  619. };
  620. });
  621. }
  622. loadingDialog.value = false;
  623. },
  624. (err) => {
  625. console.log(err);
  626. loadingDialog.value = false;
  627. }
  628. );
  629. };
  630. const submitForm = () => {
  631. submit.value.handleSubmit(() => {
  632. loadingDialog.value = true;
  633. proxy.post("/currencyRate/edit", formData.data.list).then(
  634. () => {
  635. ElMessage({
  636. message: "保存成功",
  637. type: "success",
  638. });
  639. dialogVisible.value = false;
  640. rateStatus.value = true;
  641. getList();
  642. },
  643. (err) => {
  644. console.log(err);
  645. loadingDialog.value = false;
  646. }
  647. );
  648. });
  649. };
  650. const openChange = ref(false);
  651. const change = ref(null);
  652. const formChangeData = reactive({
  653. data: {
  654. list: [],
  655. },
  656. });
  657. const formChangeConfig = computed(() => {
  658. return [
  659. {
  660. type: "slot",
  661. prop: "currencyList",
  662. slotName: "currencyList",
  663. label: "",
  664. },
  665. ];
  666. });
  667. const changeExchangeRate = (row) => {
  668. formChangeData.data = {
  669. id: row.contractId,
  670. list: [],
  671. };
  672. if (accountCurrency.value && accountCurrency.value.length > 0) {
  673. formChangeData.data.list = accountCurrency.value.map((item) => {
  674. return {
  675. type: item.value,
  676. rate: 1,
  677. };
  678. });
  679. }
  680. loadingDialog.value = true;
  681. openChange.value = true;
  682. if (row.currencyRateJson) {
  683. let currencyRateJson = JSON.parse(row.currencyRateJson);
  684. formChangeData.data.list = formChangeData.data.list.map((item) => {
  685. for (let i = 0; i < currencyRateJson.length; i++) {
  686. if (item.type === currencyRateJson[i].type) {
  687. item.rate = currencyRateJson[i].rate;
  688. break;
  689. }
  690. }
  691. return {
  692. ...item,
  693. };
  694. });
  695. loadingDialog.value = false;
  696. } else {
  697. proxy.post("/currencyRate/list", {}).then(
  698. (res) => {
  699. if (res && res.length > 0 && formChangeData.data.list.length > 0) {
  700. formChangeData.data.list = formChangeData.data.list.map((item) => {
  701. for (let i = 0; i < res.length; i++) {
  702. if (item.type === res[i].type) {
  703. item.rate = res[i].rate;
  704. break;
  705. }
  706. }
  707. return {
  708. ...item,
  709. };
  710. });
  711. }
  712. loadingDialog.value = false;
  713. },
  714. (err) => {
  715. console.log(err);
  716. loadingDialog.value = false;
  717. }
  718. );
  719. }
  720. };
  721. const submitChangeForm = () => {
  722. change.value.handleSubmit(() => {
  723. loadingDialog.value = true;
  724. let data = {};
  725. data.id = formChangeData.data.id;
  726. data.currencyRateJson = JSON.stringify(formChangeData.data.list);
  727. proxy.post("/contract/edit", data).then(
  728. () => {
  729. ElMessage({
  730. message: "保存成功",
  731. type: "success",
  732. });
  733. openChange.value = false;
  734. getList();
  735. },
  736. (err) => {
  737. console.log(err);
  738. loadingDialog.value = false;
  739. }
  740. );
  741. });
  742. };
  743. const openBudget = ref(false);
  744. const budget = ref(null);
  745. const formBudgetData = reactive({
  746. data: {},
  747. });
  748. const formBudgetConfig = computed(() => {
  749. return [
  750. {
  751. type: "title",
  752. title: "合同信息",
  753. label: "",
  754. },
  755. {
  756. type: "input",
  757. prop: "code",
  758. label: "合同编号",
  759. itemType: "text",
  760. disabled: true,
  761. },
  762. {
  763. type: "input",
  764. prop: "customerName",
  765. label: "客户名称",
  766. itemType: "text",
  767. disabled: true,
  768. },
  769. {
  770. type: "input",
  771. prop: "userName",
  772. label: "业务员",
  773. itemType: "text",
  774. disabled: true,
  775. },
  776. {
  777. type: "title",
  778. title: "预算金额",
  779. label: "",
  780. },
  781. {
  782. type: "slot",
  783. slotName: "budgetMoney",
  784. label: "",
  785. },
  786. ];
  787. });
  788. const changeBudget = (row) => {
  789. let currency = "CNY";
  790. if (accountCurrency.value && accountCurrency.value.length > 0) {
  791. currency = accountCurrency.value[0].value;
  792. }
  793. formBudgetData.data = {
  794. contractId: row.contractId,
  795. code: row.code,
  796. customerName: row.customerName,
  797. userName: row.userName,
  798. trailerFeeCurrency: currency,
  799. trailerFee: row.trailerFee,
  800. customsFeeCurrency: currency,
  801. customsFee: row.customsFee,
  802. agencyFeeCurrency: currency,
  803. agencyFee: row.agencyFee,
  804. portMixedFeeCurrency: currency,
  805. portMixedFee: row.portMixedFee,
  806. inspectionRedPackCurrency: currency,
  807. inspectionRedPack: row.inspectionRedPack,
  808. commissionCurrency: currency,
  809. commission: row.commission,
  810. otherCurrency: currency,
  811. other: row.other,
  812. };
  813. openBudget.value = true;
  814. };
  815. const submitBudgetForm = () => {
  816. proxy.post("/contractBudget/budget", formBudgetData.data).then(() => {
  817. ElMessage({
  818. message: "保存成功",
  819. type: "success",
  820. });
  821. openBudget.value = false;
  822. getList();
  823. });
  824. };
  825. const formSearchConfig = computed(() => {
  826. return [
  827. {
  828. type: "input",
  829. label: "业务员",
  830. prop: "userName",
  831. itemWidth: 100,
  832. },
  833. {
  834. type: "input",
  835. label: "合同编号",
  836. prop: "contractCode",
  837. itemWidth: 100,
  838. },
  839. {
  840. type: "input",
  841. label: "客户名称",
  842. prop: "customerName",
  843. itemWidth: 100,
  844. },
  845. {
  846. type: "date",
  847. itemType: "datetime",
  848. label: "合同时间",
  849. prop: "beginTime",
  850. placeholder: "合同开始时间",
  851. itemWidth: 50,
  852. clearable: true,
  853. },
  854. {
  855. type: "date",
  856. itemType: "datetime",
  857. label: " ",
  858. prop: "endTime",
  859. placeholder: "合同结束时间",
  860. itemWidth: 50,
  861. clearable: true,
  862. },
  863. ];
  864. });
  865. const moreSearchDialog = ref(false);
  866. const clickMoreSearch = () => {
  867. moreSearchDialog.value = true;
  868. };
  869. const moreSearchQuery = () => {
  870. moreSearchDialog.value = false;
  871. getList();
  872. };
  873. const moreSearchReset = () => {
  874. sourceList.value.pagination = {
  875. total: 0,
  876. pageNum: sourceList.value.pagination.pageNum,
  877. pageSize: sourceList.value.pagination.pageSize,
  878. keyword: "",
  879. userId: "",
  880. userName: "",
  881. contractCode: "",
  882. customerName: "",
  883. beginTime: "",
  884. endTime: "",
  885. };
  886. moreSearchQuery();
  887. };
  888. const optionTwo = reactive({
  889. data: {
  890. tooltip: {
  891. trigger: "axis",
  892. },
  893. // legend: {
  894. // data: ["价格"],
  895. // },
  896. grid: {
  897. left: "3%",
  898. right: "6%",
  899. top: "10%",
  900. bottom: "3%",
  901. containLabel: true,
  902. },
  903. tooltip: {
  904. show: true,
  905. trigger: "axis",
  906. // 格式化函数
  907. // valueFormatter: (val) => {
  908. // return val + "aaa";
  909. // },
  910. formatter: (params, ticket, callback) => {
  911. return `
  912. ${params[0].axisValue}
  913. <br/>
  914. ${params[0].seriesName}:${params[0].data}
  915. <br/> 销售合同金额:${
  916. showRowData.value.grossProfitInfoList[params[0].dataIndex + 1]
  917. .contractAmount
  918. }
  919. <br/> 采购合同金额:${
  920. showRowData.value.grossProfitInfoList[params[0].dataIndex + 1]
  921. .purchaseAmount
  922. }`;
  923. },
  924. },
  925. // toolbox: {
  926. // feature: {
  927. // saveAsImage: {},
  928. // },
  929. // },
  930. xAxis: {
  931. type: "category",
  932. boundaryGap: false,
  933. data: [],
  934. },
  935. yAxis: {
  936. type: "value",
  937. },
  938. series: [
  939. {
  940. name: "毛利",
  941. type: "line",
  942. data: [],
  943. },
  944. ],
  945. },
  946. });
  947. const showRowData = ref({});
  948. const showEcharts = (row, index) => {
  949. showRowData.value = row;
  950. let myChart = null;
  951. myChart = echarts.init(proxy.$refs[row.contractId + index]);
  952. window.addEventListener("resize", () => {
  953. myChart.resize();
  954. });
  955. if (row.grossProfitInfoList && row.grossProfitInfoList.length > 1) {
  956. // 删除数组第一个元素
  957. // const arr = proxy.deepClone(row.grossProfitInfoList);
  958. // arr.shift();
  959. let arr = row.grossProfitInfoList.slice(1, row.grossProfitInfoList.length);
  960. optionTwo.data.xAxis.data = arr.map((item) => {
  961. return item.createTime.slice(0, 10);
  962. });
  963. optionTwo.data.series[0].data = arr.map((item) => {
  964. return item.gross;
  965. });
  966. } else {
  967. optionTwo.data.xAxis.data = [];
  968. optionTwo.data.series[0].data = [];
  969. }
  970. myChart.setOption(optionTwo.data);
  971. myChart.resize();
  972. };
  973. </script>
  974. <style lang="scss" scoped>
  975. .tenant {
  976. padding: 20px;
  977. }
  978. ::v-deep(.el-input-number .el-input__inner) {
  979. text-align: left;
  980. }
  981. .active {
  982. background: #a6dd82;
  983. color: #fff;
  984. border-radius: 4px;
  985. }
  986. .pic {
  987. object-fit: contain;
  988. width: 20px;
  989. height: 20px;
  990. cursor: pointer;
  991. vertical-align: middle;
  992. }
  993. </style>