index.vue 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  1. <template>
  2. <div class="w-[100vw] bg-white">
  3. <div
  4. v-loading="loading"
  5. class="pt-2 w-[100%] min-h-[100vh]"
  6. >
  7. <!-- <div class="text-xl text-slate-700">Cargo Consolidation Request</div> -->
  8. <el-form
  9. style="width: 100%"
  10. inline
  11. :loading="loading"
  12. @submit.prevent="getList"
  13. >
  14. <el-form-item label="ETD Range">
  15. <el-date-picker
  16. v-model="dateRange"
  17. type="daterange"
  18. unlink-panels
  19. clearable
  20. start-placeholder="Start date"
  21. end-placeholder="End date"
  22. :shortcuts="dateShortcuts"
  23. :disabled-date="pickerOptions"
  24. />
  25. </el-form-item>
  26. <el-form-item>
  27. <el-tooltip content="时间范围最好不要选太大, 不然数据太多会卡">
  28. <el-button @click="getList">Search</el-button>
  29. </el-tooltip>
  30. </el-form-item>
  31. </el-form>
  32. <el-tabs v-model="currentTab">
  33. <el-tab-pane
  34. v-for="tab in tabs"
  35. :key="tab.value"
  36. :label="tab.label"
  37. :name="tab.value"
  38. ></el-tab-pane>
  39. </el-tabs>
  40. <el-table
  41. border
  42. :data="computedList"
  43. highlight-current-row
  44. style="width: 100%"
  45. max-height="330"
  46. @row-click="($e) => getSubList($e)"
  47. >
  48. <el-table-column
  49. prop="Name"
  50. label="Voyage Name"
  51. />
  52. <el-table-column
  53. prop="Port_From"
  54. label="Port From"
  55. width="100"
  56. />
  57. <el-table-column
  58. label="Port To"
  59. prop="Port_To"
  60. width="100"
  61. />
  62. <el-table-column
  63. prop="ETD"
  64. label="ETD"
  65. width="100"
  66. />
  67. <el-table-column
  68. prop="ETA"
  69. label="ETA"
  70. width="100"
  71. />
  72. <el-table-column
  73. prop="Cut_Off_Date"
  74. label="Cut Off"
  75. width="120"
  76. />
  77. <!-- <el-table-column
  78. label="Owner"
  79. width="100"
  80. >
  81. <template #default="scope">
  82. {{ scope.row.Owner.name }}
  83. </template>
  84. </el-table-column> -->
  85. <el-table-column
  86. prop="Status"
  87. label="Status"
  88. width="100"
  89. />
  90. <el-table-column
  91. label="Last Modify Time"
  92. width="180"
  93. >
  94. <template #default="scope">
  95. {{ dayjs(scope.row.Modified_Time).format('YYYY-MM-DD HH:mm:ss') }}
  96. </template>
  97. </el-table-column>
  98. </el-table>
  99. <div
  100. v-show="currentRow.Name?.length"
  101. class="flex mt-8"
  102. >
  103. <div class="flex items-center mr-4">
  104. current clicked Voyage name:&nbsp;
  105. <div class="text-red-700 font-bold">
  106. {{ currentRow.Name }}
  107. </div>
  108. </div>
  109. <el-button
  110. v-if="currentTab === 'my_request'"
  111. size="small"
  112. @click="openBulkProductDialog"
  113. >
  114. Submit Bulk Production Request
  115. </el-button>
  116. <el-button
  117. v-if="currentTab === 'my_request'"
  118. size="small"
  119. @click="openSampleDialog"
  120. >
  121. Submit Sample Request
  122. </el-button>
  123. <el-button
  124. v-if="currentTab === 'my_request'"
  125. :disabled="subList.length < 1"
  126. size="small"
  127. type="danger"
  128. @click="resetSubList"
  129. >
  130. 放弃下方表格改动
  131. </el-button>
  132. <el-button
  133. size="small"
  134. :disabled="subList.length < 1"
  135. @click="exportSubTable"
  136. >
  137. Export Excel File
  138. </el-button>
  139. <el-button
  140. v-if="currentTab === 'my_request'"
  141. :disabled="subList.length < 1"
  142. size="small"
  143. type="primary"
  144. @click="commit"
  145. >
  146. Commit
  147. </el-button>
  148. </div>
  149. <el-table
  150. class="mt-4"
  151. :data="subList"
  152. style="width: 100%"
  153. :row-style="calcRowStyle"
  154. :empty-text="
  155. currentRow.Name?.length
  156. ? '暂无数据'
  157. : '请点击voyage表格其中一行以查询相应记录'
  158. "
  159. border
  160. >
  161. <el-table-column
  162. fixed
  163. label="CRM批次记录 (Batch Record)"
  164. width="250"
  165. >
  166. <template #default="scope">
  167. <el-select
  168. v-model="scope.row.batchRecord"
  169. :remote-method="debounce(search, 1500)"
  170. remote
  171. style="width: 100%"
  172. :loading="loading2"
  173. filterable
  174. clearable
  175. :disabled="scope.row.disableFlag"
  176. @change="($e) => onBatchRecordChange($e, scope.$index)"
  177. >
  178. <el-option
  179. v-for="option in batchListOption.concat(qcList) as any[]"
  180. :key="option.id"
  181. :value="option.id"
  182. :label="
  183. option.Name +
  184. (option.Reference ? ` - ${option.Reference}` : '')
  185. "
  186. ></el-option>
  187. </el-select>
  188. </template>
  189. </el-table-column>
  190. <el-table-column
  191. label="User Notes"
  192. width="250"
  193. fixed
  194. >
  195. <template #default="scope">
  196. <el-input
  197. v-model="scope.row.User_Notes"
  198. :rows="2"
  199. type="textarea"
  200. :disabled="scope.row.disableFlag"
  201. ></el-input>
  202. </template>
  203. </el-table-column>
  204. <el-table-column
  205. label="Sample"
  206. width="80"
  207. fixed
  208. >
  209. <template #default="scope">
  210. <el-checkbox
  211. v-model="scope.row.Sample"
  212. :disabled="scope.row.disableFlag"
  213. ></el-checkbox>
  214. </template>
  215. </el-table-column>
  216. <el-table-column
  217. label="箱数(Carton)"
  218. width="115"
  219. >
  220. <template #default="scope">
  221. <el-input
  222. v-model="scope.row.Carton"
  223. :disabled="scope.row.disableFlag"
  224. ></el-input>
  225. </template>
  226. </el-table-column>
  227. <el-table-column
  228. label="唛头 (Marks & Nos)"
  229. width="220"
  230. >
  231. <template #default="scope">
  232. <el-input
  233. v-model="scope.row.Marks_Nos"
  234. :disabled="scope.row.disableFlag"
  235. ></el-input>
  236. </template>
  237. </el-table-column>
  238. <el-table-column
  239. label="货物名称 (Description of Goods)"
  240. width="180"
  241. >
  242. <template #default="scope">
  243. <el-input
  244. v-model="scope.row.Description_of_Goods"
  245. :disabled="scope.row.disableFlag"
  246. ></el-input>
  247. </template>
  248. </el-table-column>
  249. <el-table-column
  250. label="货物材质 (Material goods)"
  251. width="250"
  252. >
  253. <template #default="scope">
  254. <el-select
  255. v-model="scope.row.Material_of_Goods"
  256. multiple
  257. :disabled="scope.row.disableFlag"
  258. >
  259. <el-option
  260. v-for="i in goodMaterialOption"
  261. :key="i"
  262. :value="i"
  263. :label="i"
  264. ></el-option>
  265. </el-select>
  266. </template>
  267. </el-table-column>
  268. <el-table-column
  269. label="数量(Qty)"
  270. width="110"
  271. >
  272. <template #default="scope">
  273. <el-input
  274. v-model="scope.row.Quantity"
  275. :disabled="scope.row.disableFlag"
  276. ></el-input>
  277. </template>
  278. </el-table-column>
  279. <el-table-column
  280. label="单价(澳币/AUD) (Unit Price)"
  281. width="220"
  282. >
  283. <template #default="scope">
  284. <el-input
  285. v-model="scope.row.Unit_Price"
  286. :disabled="scope.row.disableFlag"
  287. ></el-input>
  288. </template>
  289. </el-table-column>
  290. <el-table-column
  291. label="重量(KG)(Weight)"
  292. width="100"
  293. >
  294. <template #default="scope">
  295. <el-input
  296. v-model="scope.row.Weight"
  297. :disabled="scope.row.disableFlag"
  298. ></el-input>
  299. </template>
  300. </el-table-column>
  301. <el-table-column
  302. label="体积 m&sup3;(Cube)"
  303. width="150"
  304. >
  305. <template #default="scope">
  306. <el-input
  307. v-model="scope.row.Cube"
  308. :disabled="scope.row.disableFlag"
  309. ></el-input>
  310. </template>
  311. </el-table-column>
  312. <el-table-column
  313. label="总离岸价 (澳币/AUD)(Total FOB)"
  314. width="250"
  315. >
  316. <template #default="scope">
  317. <el-input
  318. v-model="scope.row.Total_FOB"
  319. :disabled="scope.row.disableFlag"
  320. ></el-input>
  321. </template>
  322. </el-table-column>
  323. <el-table-column
  324. label="负责人(Owner)"
  325. fixed="right"
  326. width="140"
  327. >
  328. <template #default="scope">
  329. <el-input
  330. v-model="scope.row.Requester.name"
  331. disabled
  332. ></el-input>
  333. </template>
  334. </el-table-column>
  335. <el-table-column
  336. v-if="currentTab === 'my_request'"
  337. fixed="right"
  338. label="更新时间"
  339. width="180"
  340. >
  341. <template #default="scope">
  342. <div v-if="scope.row.id">
  343. {{
  344. dayjs(scope.row.update_time || new Date()).format(
  345. 'YYYY-MM-DD HH:mm:ss',
  346. )
  347. }}
  348. </div>
  349. </template>
  350. </el-table-column>
  351. <el-table-column
  352. fixed="right"
  353. label="action"
  354. width="100"
  355. >
  356. <template #default="scope">
  357. <el-button
  358. v-if="currentTab === 'my_request'"
  359. type="danger"
  360. size="small"
  361. link
  362. @click="onDeleteRow"
  363. >
  364. 删除
  365. </el-button>
  366. <el-button
  367. size="small"
  368. link
  369. type="primary"
  370. @click="print(scope.row)"
  371. >
  372. 打印
  373. </el-button>
  374. </template>
  375. </el-table-column>
  376. </el-table>
  377. <el-dialog
  378. v-model="show"
  379. :title="(isBlukDialog ? 'Bulk Product' : 'Sample') + ' Request'"
  380. :close-on-click-modal="false"
  381. :close-on-press-escape="false"
  382. width="600px"
  383. :before-close="close"
  384. >
  385. <el-form
  386. ref="formRef"
  387. :model="form"
  388. @submit.prevent
  389. >
  390. <el-form-item
  391. v-if="isBlukDialog"
  392. label="Batch Record"
  393. prop="batchRecord"
  394. :rules="{ required: true, message: '必填项' }"
  395. >
  396. <!-- <el-select
  397. v-model="form.batchRecord"
  398. @change="($e) => onBatchRecordChange($e)"
  399. >
  400. <el-option
  401. v-for="o in batchListOption"
  402. :key="o.id"
  403. :label="o.name"
  404. :value="o.id"
  405. ></el-option>
  406. </el-select> -->
  407. <el-select
  408. v-model="form.batchRecord"
  409. :remote-method="debounce(search, 1500)"
  410. remote
  411. style="width: 100%"
  412. :loading="loading2"
  413. filterable
  414. clearable
  415. @change="($e) => onBatchRecordChange($e, -1)"
  416. >
  417. <el-option
  418. v-for="option in qcList"
  419. :key="option.id"
  420. :value="option.id"
  421. :label="option.Name + ` - ${option.Reference}`"
  422. ></el-option>
  423. </el-select>
  424. </el-form-item>
  425. <el-form-item
  426. label="User Notes"
  427. prop="User_Notes"
  428. :rules="{ required: true, message: '必填项' }"
  429. >
  430. <el-input v-model="form.User_Notes"></el-input>
  431. </el-form-item>
  432. <div class="flex justify-center">
  433. <el-button
  434. type="primary"
  435. @click="addNewSubList(formRef)"
  436. >
  437. submit
  438. </el-button>
  439. </div>
  440. </el-form>
  441. </el-dialog>
  442. <el-drawer
  443. v-model:model-value="printDrawerVisible"
  444. :size="'1050px'"
  445. :title="'打印唛 (注意先写完唛内容和宽高最后再调页数, 不然可能会很卡)'"
  446. :close-on-click-modal="false"
  447. :close-on-press-escape="false"
  448. >
  449. <comp-print
  450. v-if="printDrawerVisible"
  451. :content="[currentPrintRow.Marks_Nos || '']"
  452. :scene="'QC'"
  453. />
  454. </el-drawer>
  455. </div>
  456. </div>
  457. </template>
  458. <script lang="ts" setup>
  459. import { defineComponent, ref, watch, computed } from 'vue'
  460. import {
  461. ElButton,
  462. ElForm,
  463. ElFormItem,
  464. ElInput,
  465. ElTabs,
  466. ElTabPane,
  467. ElTable,
  468. ElTableColumn,
  469. ElDatePicker,
  470. ElTooltip,
  471. ElSelect,
  472. ElOption,
  473. ElDialog,
  474. ElCheckbox,
  475. ElMessage,
  476. ElNotification,
  477. ElDrawer,
  478. } from 'element-plus'
  479. import type { FormInstance } from 'element-plus'
  480. import cloneDeep from 'lodash.clonedeep'
  481. import dayjs from 'dayjs'
  482. import * as XLSX from 'xlsx'
  483. import request from '@/utils/axios'
  484. import debounce from 'lodash.debounce'
  485. import compPrint from '@/components/print.vue'
  486. // import { useRouter } from 'vue-router'
  487. // const $router = useRouter()
  488. // $router.push('/so-search')
  489. defineComponent({
  490. name: 'ComponentCargoConsolidationRequest',
  491. })
  492. const currentUser = ref('')
  493. const currentUserName = ref('')
  494. let show = ref(false) // 新增货物对话框
  495. let loading = ref(false)
  496. let list = ref([] as any[])
  497. let currentTab = ref('all')
  498. let tabs = [
  499. {
  500. label: 'All',
  501. value: 'all',
  502. },
  503. {
  504. label: 'Avaliable',
  505. value: 'avaliable',
  506. },
  507. {
  508. label: 'Closed Voyage',
  509. value: 'voyage_closed',
  510. },
  511. {
  512. label: 'My Request',
  513. value: 'my_request',
  514. },
  515. ]
  516. let computedList = computed(() => {
  517. return list.value.filter((i: any) => {
  518. let condition = true
  519. switch (currentTab.value) {
  520. case 'avaliable':
  521. condition = i.Status && i.Status === '可用'
  522. break
  523. case 'voyage_closed':
  524. condition = ['已截仓', '已确认', '已发出'].includes(i.Status)
  525. break
  526. }
  527. return condition
  528. })
  529. })
  530. let dateRange = ref([] as any[])
  531. const generateDateRange = (days = 7) => {
  532. const today = new Date()
  533. const endDate = new Date()
  534. endDate.setDate(today.getDate() + days)
  535. return [today, endDate].sort()
  536. }
  537. // 用来限定日期选择器不让它选太大的时间范围.
  538. const pickerOptions = computed(() => {
  539. return (time: Date) => {
  540. if (!dateRange.value || dateRange.value.length !== 2) {
  541. return false // 如果没有选择范围,则不禁用任何日期
  542. }
  543. const start = dateRange.value[0].getTime()
  544. const end = dateRange.value[1].getTime()
  545. const current = time.getTime()
  546. const maxRange = 14 * 24 * 60 * 60 * 1000 // 14天的毫秒数
  547. if (current < start) {
  548. //如果当前日期小于开始日期,不禁用,因为用户可能要修改开始日期。
  549. return false
  550. }
  551. if (end - start > maxRange) {
  552. //如果用户选中的日期超过14天,则禁用超出范围的日期
  553. if (current > start + maxRange) {
  554. return true
  555. } else {
  556. return false
  557. }
  558. }
  559. if (current > start + maxRange) {
  560. //如果当前日期大于开始日期加14天,则禁用。
  561. return true
  562. }
  563. return false
  564. }
  565. })
  566. const dateShortcuts = ref([
  567. {
  568. text: 'Next 3 days',
  569. value: generateDateRange(3),
  570. },
  571. {
  572. text: 'Last 3 days',
  573. value: generateDateRange(-3),
  574. },
  575. {
  576. text: 'Next week',
  577. value: generateDateRange(7),
  578. },
  579. {
  580. text: 'Last week',
  581. value: generateDateRange(-7),
  582. },
  583. ] as any[])
  584. dateRange.value = generateDateRange(-14) // todo 提交前改为-7
  585. const clearSubList = () => {
  586. subList.value = []
  587. subListBackup = []
  588. currentRow.value = {}
  589. }
  590. let getList = () => {
  591. loading.value = true
  592. zoho.CRM.API.coql({
  593. select_query:
  594. 'select Name,Port_From,Port_To,ETD,ETA,Cut_Off_Date,Owner,Status,Modified_Time from Sea_Freight_Table' +
  595. " where ETD between '" +
  596. `${dateRange.value.map((i) => dayjs(i).format('YYYY-MM-DD')).join("' and '")}` +
  597. "'",
  598. })
  599. .then((res: any) => {
  600. // console.log(res, 'res get list')
  601. if (Array.isArray(res.data) && res.data.length) {
  602. list.value = res.data
  603. } else if (res.status === 204) {
  604. ElMessage.info(res.statusText || 'zoho api return:' + res.status)
  605. list.value = []
  606. clearSubList()
  607. }
  608. })
  609. .finally(() => (loading.value = false))
  610. }
  611. let currentRow = ref({} as any)
  612. let subList = ref([] as any[])
  613. let subListBackup: any[] = []
  614. watch(currentTab, (value: string) => {
  615. // 切到可用tab, 但是当前行是不是 可用 状态
  616. let notAvaliable = value === 'avaliable' && currentRow.value.Status !== '可用'
  617. // 切到关闭tab, 但当前行不是‘关闭’状态
  618. let notClose =
  619. value === 'voyage_closed' &&
  620. !['已截仓', '已确认', '已发出'].includes(currentRow.value.Status)
  621. // console.log(notClose, 'notClose')
  622. if (notAvaliable || notClose) {
  623. clearSubList()
  624. }
  625. })
  626. /**
  627. * 用来增加新行的数据模版
  628. */
  629. const newLineTemplate = {
  630. addFlag: true,
  631. deleteFlag: false,
  632. batchRecord: '',
  633. disableFlag: false,
  634. // 提交表单前删掉以上字段
  635. // id: '',
  636. Sample: false,
  637. Batch_Record: {
  638. name: '',
  639. id: '',
  640. } as any,
  641. Parent_Id: {
  642. name: '',
  643. id: '',
  644. } as any,
  645. Carton: '',
  646. Marks_Nos: '',
  647. Description_of_Goods: '',
  648. Material_of_Goods: [],
  649. Quantity: '',
  650. Unit_Price: '',
  651. Weight: '',
  652. Cube: '',
  653. Total_FOB: '',
  654. Requester: { name: '', id: '' } as any,
  655. User_Notes: '',
  656. }
  657. // 用在弹窗里面给批次记录做候选项
  658. let batchListOption = computed(() =>
  659. subListBackup
  660. .filter(
  661. (i) =>
  662. i.Batch_Record && i.Batch_Record.name && i.Batch_Record.name.length,
  663. )
  664. .map((i) => {
  665. return {
  666. Name: i.Batch_Record.name || '',
  667. id: i.Batch_Record.id || '',
  668. }
  669. })
  670. // ai生成的去重逻辑.
  671. .filter(
  672. (item, index, self) =>
  673. index ===
  674. self.findIndex((t) => t.Name === item.Name && t.id === item.id),
  675. ),
  676. )
  677. let getSubList = (e: any = {}) => {
  678. if (e.id) currentRow.value = e
  679. loading.value = true
  680. zoho.CRM.API.searchRecord({
  681. Entity: 'Sea_Freight_Details',
  682. Type: 'criteria',
  683. Query: `(Parent_Id:equals:${currentRow.value.id})`,
  684. delay: false,
  685. })
  686. .then((res: any) => {
  687. if (Array.isArray(res.data) && res.data.length) {
  688. // 过滤 Requester.id === 当前用户id
  689. subListBackup = res.data
  690. .filter(
  691. (i: any) =>
  692. i.Parent_Id.id === currentRow.value.id &&
  693. (currentTab.value === 'my_request'
  694. ? i.Requester.id === currentUser.value
  695. : true),
  696. )
  697. .map((i: any) => ({
  698. ...i,
  699. Sample: i.Sample || false,
  700. batchRecord: i.Batch_Record?.id || '',
  701. // disableFlag: currentUser.value !== i.Requester.id, // 同上判断.
  702. disableFlag: false,
  703. addFlag: false,
  704. deleteFlag: false,
  705. }))
  706. subList.value = cloneDeep(subListBackup)
  707. if (subList.value.length) {
  708. newLineTemplate.Parent_Id = cloneDeep(subList.value[0].Parent_Id)
  709. } else {
  710. newLineTemplate.Parent_Id = { id: currentRow.value.id }
  711. newLineTemplate.Requester = {
  712. id: currentUser.value,
  713. name: currentUserName.value,
  714. }
  715. }
  716. }
  717. })
  718. .finally(() => (loading.value = false))
  719. }
  720. const resetSubList = () => {
  721. subList.value = cloneDeep(subListBackup)
  722. }
  723. const goodMaterialOption = ref([
  724. 'Cotton 棉',
  725. 'Iron 铁',
  726. 'Neoprene 潜水料',
  727. 'Paper 纸质',
  728. 'Plastic 塑料',
  729. 'Polyester Fibre 聚酯纤维',
  730. 'PU 聚氨酯',
  731. 'PVC 聚氯乙烯',
  732. 'Velvet 天鹅绒',
  733. 'Zinc alloy 锌合金',
  734. ])
  735. let formRef = ref<FormInstance>()
  736. let form = ref({} as any)
  737. let isBlukDialog = ref(false)
  738. const openBulkProductDialog = () => {
  739. form.value = cloneDeep(newLineTemplate)
  740. isBlukDialog.value = true
  741. show.value = true
  742. }
  743. const openSampleDialog = () => {
  744. form.value = cloneDeep(newLineTemplate)
  745. form.value.Sample = true
  746. form.value.Requester = { id: currentUser.value, name: currentUserName.value }
  747. isBlukDialog.value = false
  748. show.value = true
  749. }
  750. const close = (done = {} as any) => {
  751. if (formRef.value && typeof formRef.value.clearValidate === 'function') {
  752. formRef.value.clearValidate()
  753. }
  754. if (typeof done === 'function') done()
  755. }
  756. const addNewSubList = (formEl: FormInstance | undefined) => {
  757. if (!formEl) return
  758. formEl.validate((valid: boolean) => {
  759. if (!valid) return
  760. subList.value.push(cloneDeep(form.value))
  761. show.value = false
  762. isBlukDialog.value = false
  763. form.value = {}
  764. })
  765. }
  766. const onDeleteRow = (row: any) => {
  767. row.deleteFlag = true
  768. ElNotification({
  769. type: 'warning',
  770. title: '已标记删除',
  771. duration: 3000,
  772. message: '点 提交 按钮后会正式删除. 误操作请点击 放弃改动.',
  773. })
  774. }
  775. const onBatchRecordChange = ($e: string, line = -1) => {
  776. const temp = qcList.value.filter((i) => i.id === $e)
  777. let result: any = {}
  778. if (temp.length) {
  779. result = cloneDeep(temp[0])
  780. }
  781. if (line > -1) {
  782. // 主页面数据编辑
  783. subList.value[line].Batch_Record = { id: result.id, name: result.Name }
  784. if (result.Owner) {
  785. subList.value[line].Requester = {
  786. name: result.Owner.name,
  787. id: result.Owner.id,
  788. }
  789. }
  790. } else {
  791. form.value.Requester = {
  792. name: result.Owner.name,
  793. id: result.Owner.id,
  794. }
  795. form.value.Batch_Record = { id: result.id, name: result.Name }
  796. }
  797. }
  798. // 给子表格加红绿背景. 颜色用的tailwind的 red green
  799. const calcRowStyle = ($e: any) => {
  800. const result = {} as any
  801. if ($e.row.addFlag) result['background-color'] = 'rgb(187, 247, 208)'
  802. if ($e.row.deleteFlag) result['background-color'] = 'rgb(254, 202, 202)'
  803. return result
  804. }
  805. const commit = () => {
  806. const result = cloneDeep(subList.value)
  807. .filter((i) => !i.deleteFlag)
  808. .map((i) => {
  809. return {
  810. id: i.id,
  811. Sample: i.Sample || false,
  812. Batch_Record: i.batchRecord
  813. ? {
  814. name: i.Batch_Record.name,
  815. id: i.Batch_Record.id,
  816. }
  817. : '',
  818. Parent_Id: {
  819. name: i.Parent_Id.name,
  820. id: i.Parent_Id.id || '',
  821. },
  822. Material_of_Goods: i.Material_of_Goods,
  823. Requester: {
  824. name: i.Requester.name,
  825. id: i.Requester.id || '',
  826. },
  827. Sales_Person: i.Requester.name || '',
  828. Carton: i.Carton || '',
  829. Marks_Nos: i.Marks_Nos || '',
  830. Description_of_Goods: i.Description_of_Goods || '',
  831. Quantity: i.Quantity || '',
  832. Unit_Price: i.Unit_Price || '',
  833. Weight: i.Weight || '',
  834. Cube: i.Cube || '',
  835. Total_FOB: i.Total_FOB || '',
  836. User_Notes: i.User_Notes || '',
  837. }
  838. })
  839. loading.value = true
  840. request
  841. .post('/sea_freight/updateSeaFreightData', {
  842. id: newLineTemplate.Parent_Id.id,
  843. Sea_Freight_array: result,
  844. })
  845. .then((res) => {
  846. if (res.data.code === 1) {
  847. ElNotification({
  848. title: '保存成功',
  849. message: '正在刷新数据',
  850. duration: 3000,
  851. })
  852. getSubList(currentRow.value)
  853. } else {
  854. ElMessage.error('保存出错')
  855. loading.value = false
  856. }
  857. })
  858. .catch((e) => {
  859. console.log(e, 'commit error')
  860. loading.value = false
  861. })
  862. }
  863. let printDrawerVisible = ref(false)
  864. let currentPrintRow = ref({} as any)
  865. const print = (row: any) => {
  866. currentPrintRow.value = row
  867. printDrawerVisible.value = true
  868. }
  869. const exportSubTable = () => {
  870. const headers = [
  871. 'id',
  872. 'CRM批次记录 (Batch Record)',
  873. 'Sample',
  874. '箱数(Carton)',
  875. '唛头 (Marks & Nos)',
  876. '货物名称 (Description of Goods)',
  877. '货物材质 (Material goods)',
  878. '数量(Qty)',
  879. '单价(澳币/AUD) (Unit Price)',
  880. '重量(KG)(Weight)',
  881. '体积 m³(Cube)',
  882. '总离岸价 (澳币/AUD)(Total FOB)',
  883. 'User_Notes',
  884. '负责人(Owner)',
  885. ]
  886. // console.log(subList.value, 'subList.value')
  887. const data: any[] = subList.value.map((i) => {
  888. return {
  889. id: i.id,
  890. 'CRM批次记录 (Batch Record)': i.Batch_Record?.name || '',
  891. Sample: i.Sample ? 'true' : '',
  892. '箱数(Carton)': i.Carton || '',
  893. '唛头 (Marks & Nos)': i.Marks_Nos || '',
  894. '货物名称 (Description of Goods)': i.Description_of_Goods || '',
  895. '货物材质 (Material goods)': i.Material_of_Goods,
  896. '数量(Qty)': i.Quantity || '',
  897. '单价(澳币/AUD) (Unit Price)': i.Unit_Price || '',
  898. '重量(KG)(Weight)': i.Weight || '',
  899. '体积 m³(Cube)': i.Cube || '',
  900. '总离岸价 (澳币/AUD)(Total FOB)': i.Total_FOB || '',
  901. User_Notes: i.User_Notes || '',
  902. '负责人(Owner)': i.Requester.name || '',
  903. }
  904. })
  905. if (data.length === 0) {
  906. throw new Error('Invalid data: Data array is empty.')
  907. }
  908. const worksheetData = []
  909. if (headers && headers.length > 0) {
  910. worksheetData.push(headers)
  911. } else {
  912. worksheetData.push(Object.keys(data[0]))
  913. }
  914. data.forEach((row) => {
  915. worksheetData.push(Object.values(row))
  916. })
  917. const wb = XLSX.utils.book_new()
  918. let ws = XLSX.utils.aoa_to_sheet(worksheetData)
  919. ws['!cols'] = [
  920. { wpx: 120 },
  921. { wpx: 450 },
  922. { wpx: 80 },
  923. { wpx: 80 },
  924. { wpx: 80 },
  925. { wpx: 120 },
  926. { wpx: 100 },
  927. { wpx: 80 },
  928. { wpx: 80 },
  929. { wpx: 80 },
  930. { wpx: 80 },
  931. { wpx: 80 },
  932. { wpx: 350 },
  933. { wpx: 100 },
  934. ]
  935. XLSX.utils.book_append_sheet(wb, ws, 'Sheet1')
  936. XLSX.writeFile(wb, 'test.xlsx')
  937. }
  938. let qcList = ref([] as any[])
  939. let loading2 = ref(false)
  940. const search = (keyword: string) => {
  941. if (keyword.length < 2) return
  942. loading2.value = true
  943. zoho.CRM.API.searchRecord({
  944. Entity: 'QC_Record',
  945. Type: 'criteria',
  946. Query: `(Reference:in:${keyword})or(Reference:starts_with:${keyword})or(Purchase_Order.name:in:${keyword})or(Purchase_Order.name:starts_with:${keyword})`,
  947. delay: false,
  948. })
  949. .then((res: any) => {
  950. if (Array.isArray(res.data) && res.data.length) {
  951. qcList.value = res.data
  952. } else {
  953. qcList.value = []
  954. ElMessage.warning('No Data Found')
  955. }
  956. })
  957. .finally(() => (loading2.value = false))
  958. }
  959. // @ts-ignore
  960. const zoho = window.ZOHO
  961. zoho.embeddedApp.on('PageLoad', function () {
  962. zoho.CRM.CONFIG.getCurrentUser().then(function (data: any) {
  963. if (Array.isArray(data.users) && data.users.length) {
  964. const user = data.users[0]
  965. currentUser.value = user.id
  966. currentUserName.value = user.full_name || ''
  967. getList()
  968. }
  969. })
  970. })
  971. zoho.embeddedApp.init()
  972. </script>