order.vue 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  1. <template>
  2. <div>
  3. <div style="padding: 8px; text-align: center" v-if="formData.data.code || formData.data.wlnCode">
  4. <span style="font-size: 18px; font-weight: 700">{{ formData.data.code }} </span>
  5. <span style="font-size: 18px; font-weight: 700" v-if="formData.data.wlnCode"> ({{ formData.data.wlnCode }})</span>
  6. </div>
  7. <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="submit">
  8. <template #type>
  9. <div style="width: 100%">
  10. <el-radio-group v-model="formData.data.type">
  11. <el-radio v-for="(itemType, index) in typeList" :key="index" :label="itemType.dictKey">{{ itemType.dictValue }}</el-radio>
  12. </el-radio-group>
  13. </div>
  14. </template>
  15. <template #departmentId>
  16. <div style="width: 100%">
  17. <el-select v-model="formData.data.departmentId" placeholder="请选择事业部" clearable style="width: 100%">
  18. <el-option v-for="item in departmentList" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" />
  19. </el-select>
  20. </div>
  21. </template>
  22. <template #deliveryAddress>
  23. <div style="width: 100%">
  24. <el-row>
  25. <el-col :span="3">
  26. <el-form-item label-width="0" prop="province" style="width: 100%">
  27. <el-input v-model="formData.data.province" placeholder="请输入省" />
  28. </el-form-item>
  29. </el-col>
  30. <el-col :span="3">
  31. <el-form-item label-width="0" prop="city" style="width: 100%">
  32. <el-input v-model="formData.data.city" placeholder="请输入市" />
  33. </el-form-item>
  34. </el-col>
  35. <el-col :span="3">
  36. <el-form-item label-width="0" prop="county" style="width: 100%">
  37. <el-input v-model="formData.data.county" placeholder="请输入区/县" />
  38. </el-form-item>
  39. </el-col>
  40. <el-col :span="11">
  41. <el-form-item label-width="0" prop="detailedAddress" style="width: 100%">
  42. <el-input v-model="formData.data.detailedAddress" placeholder="请输入详细地址" />
  43. </el-form-item>
  44. </el-col>
  45. <el-col :span="4">
  46. <el-form-item label-width="0" prop="postcode" style="width: 100%">
  47. <el-input v-model="formData.data.postcode" placeholder="请输入邮编" />
  48. </el-form-item>
  49. </el-col>
  50. </el-row>
  51. </div>
  52. </template>
  53. <template #consignee>
  54. <div style="width: 100%">
  55. <el-row>
  56. <el-col :span="6">
  57. <el-form-item label-width="0" prop="consignee" style="width: 100%">
  58. <el-input v-model="formData.data.consignee" placeholder="请输入联系人" />
  59. </el-form-item>
  60. </el-col>
  61. <el-col :span="6">
  62. <el-form-item label-width="0" prop="consigneeNumber" style="width: 100%">
  63. <el-input v-model="formData.data.consigneeNumber" placeholder="请输入联系电话" />
  64. </el-form-item>
  65. </el-col>
  66. </el-row>
  67. </div>
  68. </template>
  69. <template #orderSkuList>
  70. <div style="width: 100%; padding: 0 20px">
  71. <div style="margin-bottom: 10px" v-if="!formOption.disabled">
  72. <el-button type="primary" size="small" @click="clickAddProduct()">选择产品</el-button>
  73. </div>
  74. <div v-for="(item, index) in formData.data.orderSkuList" :key="index" style="margin-bottom: 20px">
  75. <div style="border: 1px solid #edf0f5">
  76. <el-table :data="[item]" :row-style="{ height: '35px' }" header-row-class-name="tableHeader" :cell-class-name="cellStyleName">
  77. <el-table-column label="产品" width="280">
  78. <template #default="{ row }">
  79. <div style="width: 100%">
  80. <div style="line-height: 35px" v-if="!formOption.disabled">
  81. <span style="color: black; font-weight: 700">库存数量: </span>
  82. <span>{{ item.inventoryQuantity }}</span>
  83. </div>
  84. <div style="line-height: 35px">
  85. <span style="color: black; font-weight: 700">商品名称: </span>
  86. <span>{{ item.wlnSkuName }}</span>
  87. </div>
  88. <div style="line-height: 35px">
  89. <span style="color: black; font-weight: 700">品号: </span>
  90. <span>{{ item.code }}</span>
  91. </div>
  92. <div style="line-height: 35px; word-break: break-all">
  93. <span style="color: black; font-weight: 700">品名: </span>
  94. <span>{{ item.name }}</span>
  95. </div>
  96. <div style="line-height: 35px; display: flex">
  97. <span style="width: 37px; color: black; font-weight: 700">数量: </span>
  98. <el-form-item
  99. :prop="'orderSkuList.' + index + '.quantity'"
  100. :rules="rules.quantity"
  101. :inline-message="true"
  102. style="width: calc(100% - 37px)">
  103. <el-input-number
  104. onmousewheel="return false;"
  105. v-model="row.quantity"
  106. placeholder="数量"
  107. style="width: 100%"
  108. :controls="false"
  109. :min="0"
  110. :precision="0"
  111. @change="changeQuantity(index)" />
  112. </el-form-item>
  113. </div>
  114. <div style="line-height: 35px">
  115. <span style="color: black; font-weight: 700">加工费: </span>
  116. <span>{{ item.customProcessingFee }}</span>
  117. </div>
  118. <div style="line-height: 35px">
  119. <span style="color: black; font-weight: 700">代发费: </span>
  120. <span>{{ item.lssueFee }}</span>
  121. </div>
  122. <div style="line-height: 35px">
  123. <span style="color: black; font-weight: 700">快递包材费: </span>
  124. <span>{{ item.deliveryMaterialsFee }}</span>
  125. </div>
  126. <div style="line-height: 35px">
  127. <span style="color: black; font-weight: 700">包装人工费: </span>
  128. <span>{{ item.packingLabor }}</span>
  129. </div>
  130. <div style="line-height: 35px">
  131. <span style="color: black; font-weight: 700">管理费: </span>
  132. <span>{{ item.managementFee }}</span>
  133. </div>
  134. <div style="line-height: 35px">
  135. <span style="color: black; font-weight: 700">单价: </span>
  136. <span>{{ item.unitPrice }}</span>
  137. </div>
  138. <div style="line-height: 35px">
  139. <span style="color: black; font-weight: 700">小计: </span>
  140. <span>{{ getSubtotal(item) }}</span>
  141. </div>
  142. <div style="line-height: 35px">
  143. <span style="width: 37px; color: black; font-weight: 700">打印: </span>
  144. <el-form-item
  145. :prop="'orderSkuList.' + index + '.printType'"
  146. :rules="rules.printType"
  147. :inline-message="true"
  148. style="width: calc(100% - 37px)">
  149. <el-radio-group v-model="item.printType" @change="changeQuantity(index)">
  150. <el-radio v-for="(itemType, index) in printType" :key="index" :label="itemType.dictKey">{{ itemType.dictValue }}</el-radio>
  151. </el-radio-group>
  152. </el-form-item>
  153. </div>
  154. </div>
  155. </template>
  156. </el-table-column>
  157. <el-table-column label="产品图稿" width="320">
  158. <template #default="{ row }">
  159. <div style="display: flex; width: 100%">
  160. <div style="width: 80px">设计图:</div>
  161. <div style="width: calc(100% - 80px)">
  162. <el-image
  163. fit="scale-down"
  164. style="width: 148px; height: 148px; margin-right: 10px; cursor: pointer"
  165. v-if="row.blueprint"
  166. :src="row.blueprint"
  167. @click="openFile(row.blueprint)" />
  168. <div style="display: flex" v-if="!formOption.disabled">
  169. <el-button type="primary" @click="clickDrawingFile(index)" text>选择图稿</el-button>
  170. <el-upload
  171. :show-file-list="false"
  172. action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
  173. :data="uploadImgData"
  174. :before-upload="uploadImgFile"
  175. :on-success="
  176. (response, uploadFile) => {
  177. return handleImgSuccess(uploadFile, index);
  178. }
  179. "
  180. style="width: 100%"
  181. accept=".docx,.jpg,.jpeg,.png,.GIF,.JPG,.PNG">
  182. <el-button type="primary" style="margin-left: 12px" text>上传图片</el-button>
  183. </el-upload>
  184. </div>
  185. </div>
  186. </div>
  187. <div style="display: flex; margin-top: 20px; width: 100%">
  188. <div style="width: 80px">图稿文件:</div>
  189. <div style="width: calc(100% - 80px)">
  190. <a
  191. style="color: #409eff; cursor: pointer; word-break: break-all; margin-right: 10px"
  192. @click="openFile(row.productionDocument)"
  193. v-if="row.productionDocument">
  194. {{ row.productionDocument }}
  195. </a>
  196. <div style="display: flex" v-if="!formOption.disabled">
  197. <el-button type="primary" @click="clickDrawingFile(index)" text>选择图稿</el-button>
  198. <el-upload
  199. :show-file-list="false"
  200. action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
  201. :data="uploadData"
  202. :before-upload="uploadFile"
  203. :on-success="
  204. (response, uploadFile) => {
  205. return handleSuccess(uploadFile, index);
  206. }
  207. "
  208. style="width: 100%">
  209. <el-button type="primary" style="margin-left: 12px" text>上传文件</el-button>
  210. </el-upload>
  211. </div>
  212. </div>
  213. </div>
  214. <div style="font-weight: 700; margin-top: 20px">产品不干胶图稿</div>
  215. <div style="display: flex; width: 100%">
  216. <div style="width: 80px">不干胶图片:</div>
  217. <div style="width: calc(100% - 80px)">
  218. <el-image
  219. fit="scale-down"
  220. style="width: 148px; height: 148px; margin-right: 10px; cursor: pointer"
  221. v-if="row.selfAdhesiveStickerFile && row.selfAdhesiveStickerFile.fileUrl"
  222. :src="row.selfAdhesiveStickerFile.fileUrl"
  223. @click="openFile(row.selfAdhesiveStickerFile.fileUrl)" />
  224. <div style="display: flex" v-if="!formOption.disabled">
  225. <el-upload
  226. :show-file-list="false"
  227. action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
  228. :data="uploadAdhesiveData"
  229. :before-upload="uploadAdhesiveFile"
  230. :on-success="
  231. (response, uploadFile) => {
  232. return handleAdhesiveSuccess(uploadFile, index);
  233. }
  234. "
  235. style="width: 100%">
  236. <el-button type="primary" text>上传文件</el-button>
  237. </el-upload>
  238. </div>
  239. </div>
  240. </div>
  241. </template>
  242. </el-table-column>
  243. <el-table-column label="包材配件/单品" min-width="600">
  244. <template #default="{ row }">
  245. <div style="width: 100%">
  246. <div style="margin-bottom: 10px" v-if="!formOption.disabled || route.query.processType == 10">
  247. <el-form label-width="0" :model="formData.data" v-if="route.query.processType == 10">
  248. <el-button type="primary" size="small" @click="clickPackingFittings(index)">选择包材配件</el-button>
  249. </el-form>
  250. <el-button type="primary" size="small" @click="clickPackingFittings(index)" v-else>选择包材配件</el-button>
  251. </div>
  252. <el-table :data="row.orderSkuBomList" :row-style="{ height: '35px' }" header-row-class-name="tableHeader">
  253. <el-table-column label="单价¥" width="70">
  254. <template #default="props">
  255. <div>
  256. <span>{{ moneyFormat(props.row.unitPrice, 2) }}</span>
  257. </div>
  258. </template>
  259. </el-table-column>
  260. <el-table-column label="数量" width="90">
  261. <template #default="props">
  262. <el-form label-width="0" :model="formData.data" v-if="route.query.processType == 10">
  263. <el-form-item
  264. :prop="'orderSkuList.' + index + '.orderSkuBomList.' + props.$index + '.quantity'"
  265. :rules="rules.quantity"
  266. :inline-message="true"
  267. style="width: 100%"
  268. :disabled="true">
  269. <el-input-number
  270. onmousewheel="return false;"
  271. v-model="props.row.quantity"
  272. placeholder="数量"
  273. style="width: 100%"
  274. :controls="false"
  275. :min="0" />
  276. </el-form-item>
  277. </el-form>
  278. <el-form-item
  279. v-else
  280. :prop="'orderSkuList.' + index + '.orderSkuBomList.' + props.$index + '.quantity'"
  281. :rules="rules.quantity"
  282. :inline-message="true"
  283. style="width: 100%"
  284. :disabled="true">
  285. <el-input-number
  286. onmousewheel="return false;"
  287. v-model="props.row.quantity"
  288. placeholder="数量"
  289. style="width: 100%"
  290. :controls="false"
  291. :min="0" />
  292. </el-form-item>
  293. </template>
  294. </el-table-column>
  295. <el-table-column label="名称" prop="bomSpecName" min-width="130" />
  296. <el-table-column label="总量" width="70">
  297. <template #default="props">
  298. {{ computeQuantity(index, props.$index) }}
  299. </template>
  300. </el-table-column>
  301. <el-table-column label="小计¥" width="100">
  302. <template #default="props">
  303. {{ moneyFormat(computeMoney(index, props.$index), 2) }}
  304. </template>
  305. </el-table-column>
  306. <el-table-column label="操作" align="center" fixed="right" width="60" v-if="!formOption.disabled || route.query.processType == 10">
  307. <template #default="props">
  308. <el-form label-width="0" :model="formData.data" v-if="route.query.processType == 10">
  309. <el-button type="danger" @click="clickDeletePackingFittings(index, props.$index)" text>删除</el-button>
  310. </el-form>
  311. <el-button type="danger" v-else @click="clickDeletePackingFittings(index, props.$index)" text>删除</el-button>
  312. </template>
  313. </el-table-column>
  314. </el-table>
  315. </div>
  316. </template>
  317. </el-table-column>
  318. <el-table-column label="包装要求" min-width="500">
  319. <template #default="{}">
  320. <div v-if="formOption.disabled">
  321. <div v-html="getStyle(item.packageRemark)"></div>
  322. </div>
  323. <Editor
  324. v-else
  325. :value="item.packageRemark"
  326. @updateValue="
  327. (val) => {
  328. return updatePackageRemark(val, index);
  329. }
  330. "
  331. :ref="'editor_' + index" />
  332. </template>
  333. </el-table-column>
  334. <el-table-column label="操作" align="center" fixed="right" width="60" v-if="!formOption.disabled">
  335. <template #default="{}">
  336. <el-button type="danger" @click="clickDelete(index)" text>删除</el-button>
  337. </template>
  338. </el-table-column>
  339. </el-table>
  340. </div>
  341. </div>
  342. </div>
  343. </template>
  344. <template #deliveryTime>
  345. <div style="width: 100%">
  346. <el-date-picker
  347. v-model="formData.data.deliveryTime"
  348. type="datetime"
  349. placeholder="请选择交货日期"
  350. value-format="YYYY-MM-DD HH:mm:ss"
  351. style="width: 100%" />
  352. </div>
  353. </template>
  354. <template #totalMonet>
  355. <div style="width: 100%; margin-left: 30px">
  356. <div>
  357. <span style="font-weight: 700; color: #6c88f1">产品总金额: ¥{{ moneyFormat(calculatedAmount("unitPrice"), 2) }}</span>
  358. <span style="font-weight: 700; color: #6c88f1; margin-left: 40px">
  359. 定制加工费: ¥{{ moneyFormat(calculatedAmount("customProcessingFee"), 2) }}
  360. </span>
  361. <span style="font-weight: 700; color: #6c88f1; margin-left: 40px">代发费: ¥{{ moneyFormat(calculatedAmount("lssueFee"), 2) }}</span>
  362. <span style="font-weight: 700; color: #6c88f1; margin-left: 40px">
  363. 快递包材费: ¥{{ moneyFormat(calculatedAmount("deliveryMaterialsFee"), 2) }}
  364. </span>
  365. <span style="font-weight: 700; color: #6c88f1; margin-left: 40px">包装人工费: ¥{{ moneyFormat(calculatedAmount("packingLabor"), 2) }}</span>
  366. <span style="font-weight: 700; color: #6c88f1; margin-left: 40px">包材费: ¥{{ moneyFormat(calculatedPackagingMaterialCost(), 2) }}</span>
  367. <span style="font-weight: 700; color: #6c88f1; margin-left: 40px">管理费: ¥{{ moneyFormat(calculatedAmount("managementFee"), 2) }}</span>
  368. <span style="font-weight: 700; color: #6c88f1; margin-left: 40px">外箱包装费: ¥{{ moneyFormat(calculatedOuterBoxPackingFee(), 2) }}</span>
  369. </div>
  370. <div style="padding: 8px 0 0 0">
  371. <span style="font-weight: 700; color: red">订单总金额(含税): ¥{{ moneyFormat(calculatedTotalAmount(), 2) }}</span>
  372. </div>
  373. </div>
  374. </template>
  375. <template #attachments>
  376. <div style="width: 100%">
  377. <el-upload
  378. v-model:fileList="fileList"
  379. action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
  380. :data="uploadFileData"
  381. multiple
  382. :before-upload="beforeUpload"
  383. :on-success="onSuccessFile"
  384. :on-preview="onPreviewFile">
  385. <el-button style="background: #20b2aa; color: #fff; border: 1px solid #20b2aa">上传</el-button>
  386. </el-upload>
  387. </div>
  388. </template>
  389. <template #remark>
  390. <div style="width: 100%">
  391. <div style="margin: 0 2vw" v-if="formOption.disabled">
  392. <div v-html="getStyle(formData.data.remark)"></div>
  393. </div>
  394. <Editor v-else :value="formData.data.remark" @updateValue="updateValue" ref="editor" />
  395. </div>
  396. </template>
  397. </byForm>
  398. <el-dialog title="选择产品" v-if="openProduct" v-model="openProduct" width="90%">
  399. <SelectProduct :selectStatus="true" :type="'null'" @selectProduct="selectProduct"></SelectProduct>
  400. <template #footer>
  401. <el-button @click="openProduct = false" size="large">关 闭</el-button>
  402. </template>
  403. </el-dialog>
  404. <el-dialog title="选择包材配件" v-if="openPackingFittings" v-model="openPackingFittings" width="90%">
  405. <SelectBOM :selectStatus="true" :bomClassifyIdList="[2, 3]" @selectBOM="selectPackingFittings"></SelectBOM>
  406. <template #footer>
  407. <el-button @click="openPackingFittings = false" size="large">关 闭</el-button>
  408. </template>
  409. </el-dialog>
  410. <el-dialog title="选择图稿文件" v-if="openDrawingFile" v-model="openDrawingFile" width="70%">
  411. <SelectPicture @selectPic="selectPic"></SelectPicture>
  412. <template #footer>
  413. <el-button @click="openDrawingFile = false" size="large">关 闭</el-button>
  414. </template>
  415. </el-dialog>
  416. </div>
  417. </template>
  418. <script setup>
  419. import byForm from "/src/components/byForm/index";
  420. import { ElMessage } from "element-plus";
  421. import Editor from "/src/components/Editor/index.vue";
  422. import { useRoute } from "vue-router";
  423. import SelectProduct from "/src/views/group/product/management/index";
  424. import SelectBOM from "/src/views/group/BOM/management/index";
  425. import SelectPicture from "/src/components/select-picture/index.vue";
  426. const { proxy } = getCurrentInstance();
  427. // 接收父组件的传值
  428. const props = defineProps({
  429. queryData: Object,
  430. });
  431. const route = useRoute();
  432. const submit = ref(null);
  433. const departmentList = ref([]);
  434. const judgeStatus = () => {
  435. if (route.query.processType == 20 || route.query.processType == 10) {
  436. return true;
  437. }
  438. if (props.queryData.recordList && props.queryData.recordList.length > 0) {
  439. let data = props.queryData.recordList.filter((item) => item.status === 2 && item.nodeType !== 1);
  440. if (data && data.length > 0) {
  441. return true;
  442. }
  443. }
  444. return false;
  445. };
  446. const formOption = reactive({
  447. inline: true,
  448. labelWidth: "120px",
  449. itemWidth: 100,
  450. rules: [],
  451. labelPosition: "right",
  452. });
  453. const formData = reactive({
  454. data: {
  455. remark: "",
  456. type: 1,
  457. orderSkuList: [],
  458. fileList: [],
  459. },
  460. });
  461. const formConfig = computed(() => {
  462. return [
  463. {
  464. type: "title",
  465. title: "产品",
  466. label: "",
  467. },
  468. {
  469. type: "slot",
  470. prop: "orderSkuList",
  471. slotName: "orderSkuList",
  472. },
  473. {
  474. type: "title",
  475. title: "类型",
  476. label: "",
  477. },
  478. {
  479. type: "slot",
  480. prop: "type",
  481. slotName: "type",
  482. label: "订单类型",
  483. },
  484. {
  485. type: "slot",
  486. prop: "departmentId",
  487. slotName: "departmentId",
  488. label: "事业部",
  489. itemWidth: 25,
  490. },
  491. formOption.disabled
  492. ? {}
  493. : {
  494. type: "title",
  495. title: "地址",
  496. label: "",
  497. },
  498. formOption.disabled
  499. ? {}
  500. : {
  501. type: "slot",
  502. slotName: "deliveryAddress",
  503. label: "收货地址",
  504. },
  505. formOption.disabled
  506. ? {}
  507. : {
  508. type: "slot",
  509. slotName: "consignee",
  510. label: "收货人",
  511. },
  512. {
  513. type: "title",
  514. title: "贸易",
  515. label: "",
  516. },
  517. {
  518. type: "slot",
  519. prop: "deliveryTime",
  520. slotName: "deliveryTime",
  521. label: "交货时间",
  522. itemWidth: 25,
  523. },
  524. {
  525. type: "select",
  526. label: "选择快递",
  527. prop: "expressDeliveryId",
  528. data: proxy.useUserStore().allDict["express_delivery"],
  529. itemWidth: 25,
  530. clearable: true,
  531. },
  532. {
  533. type: "select",
  534. label: "店铺来源",
  535. prop: "sourcePlatform",
  536. data: proxy.useUserStore().allDict["source_platform"],
  537. itemWidth: 25,
  538. clearable: true,
  539. },
  540. {
  541. type: "select",
  542. label: "店铺名称",
  543. prop: "shopName",
  544. data: proxy.useUserStore().allDict["shop_name"],
  545. itemWidth: 25,
  546. clearable: true,
  547. },
  548. {
  549. type: "title",
  550. title: "总计",
  551. label: "",
  552. },
  553. {
  554. type: "slot",
  555. prop: "totalMonet",
  556. slotName: "totalMonet",
  557. },
  558. {
  559. type: "title",
  560. title: "附件",
  561. label: "",
  562. },
  563. {
  564. type: "slot",
  565. slotName: "attachments",
  566. label: "附件",
  567. },
  568. {
  569. type: "title",
  570. title: "订单备注",
  571. label: "",
  572. },
  573. {
  574. type: "slot",
  575. slotName: "remark",
  576. },
  577. ];
  578. });
  579. const rules = ref({
  580. province: [{ required: true, message: "请输入省", trigger: "blur" }],
  581. detailedAddress: [{ required: true, message: "请输入详细地址", trigger: "blur" }],
  582. consignee: [{ required: true, message: "请输入联系人", trigger: "blur" }],
  583. consigneeNumber: [{ required: true, message: "请输入联系电话", trigger: "blur" }],
  584. deliveryTime: [{ required: true, message: "请选择交货时间", trigger: "change" }],
  585. expressDeliveryId: [{ required: true, message: "请选择快递", trigger: "change" }],
  586. sourcePlatform: [{ required: true, message: "请选择店铺来源", trigger: "change" }],
  587. shopName: [{ required: true, message: "请选择店铺", trigger: "change" }],
  588. quantity: [{ required: true, message: "请输入数量", trigger: "blur" }],
  589. type: [{ required: true, message: "请选择订单类型", trigger: "change" }],
  590. departmentId: [{ required: true, message: "请选择事业部", trigger: "change" }],
  591. });
  592. const getDemandData = () => {
  593. proxy.post("/department/page", { pageNum: 1, pageSize: 999 }).then((res) => {
  594. if (res.rows && res.rows.length > 0) {
  595. departmentList.value = res.rows.map((item) => {
  596. return {
  597. dictKey: item.id,
  598. dictValue: item.name,
  599. };
  600. });
  601. }
  602. });
  603. };
  604. getDemandData();
  605. const drawingFileIndex = ref(0);
  606. const openDrawingFile = ref(false);
  607. const clickDrawingFile = (index) => {
  608. drawingFileIndex.value = index;
  609. openDrawingFile.value = true;
  610. };
  611. const selectPic = (row) => {
  612. formData.data.orderSkuList[drawingFileIndex.value].blueprint = row.imgUrl;
  613. formData.data.orderSkuList[drawingFileIndex.value].productionDocument = row.fileUrl;
  614. formData.data.orderSkuList[drawingFileIndex.value].artworkLibraryId = row.id;
  615. ElMessage({ message: "选择完成", type: "success" });
  616. openDrawingFile.value = false;
  617. };
  618. const openFile = (path) => {
  619. window.open(path);
  620. };
  621. const updatePackageRemark = (val, index) => {
  622. formData.data.orderSkuList[index].packageRemark = val;
  623. };
  624. const clickDelete = (index) => {
  625. formData.data.orderSkuList.splice(index, 1);
  626. };
  627. const updateValue = (val) => {
  628. formData.data.remark = val;
  629. };
  630. const getStyle = (text) => {
  631. if (text) {
  632. return text.replace(/\n|\r\n/g, "<br>");
  633. } else {
  634. return "";
  635. }
  636. };
  637. const openProduct = ref(false);
  638. const clickAddProduct = () => {
  639. openProduct.value = true;
  640. };
  641. const printType = ref([
  642. {
  643. dictKey: 1,
  644. dictValue: "单面",
  645. },
  646. {
  647. dictKey: 2,
  648. dictValue: "双面",
  649. },
  650. ]);
  651. const typeList = ref([
  652. {
  653. dictKey: 1,
  654. dictValue: "自主订单",
  655. },
  656. {
  657. dictKey: 2,
  658. dictValue: "委外订单",
  659. },
  660. ]);
  661. const skuDetail = ref({});
  662. const selectProduct = (row, SKU) => {
  663. if (row.id) {
  664. let list = formData.data.orderSkuList.filter((item) => item.skuSpecId === row.id && item.bomSpecId === row.bomSpecId);
  665. if (list && list.length > 0) {
  666. return ElMessage("该产品已添加");
  667. }
  668. if (skuDetail.value && skuDetail.value.id === SKU.id) {
  669. pushProduct(skuDetail.value, SKU, row);
  670. } else {
  671. proxy.post("/sku/detail", { id: SKU.id }).then((res) => {
  672. skuDetail.value = res;
  673. pushProduct(res, SKU, row);
  674. });
  675. }
  676. } else {
  677. ElMessage("添加失败");
  678. }
  679. };
  680. const pushProduct = async (res, SKU, row) => {
  681. let data = proxy.deepClone(res);
  682. let orderSkuBomList = [];
  683. if (data.skuSpecList && data.skuSpecList.length > 0) {
  684. let listTwo = data.skuSpecList.filter((item) => item.id === row.id);
  685. if (listTwo && listTwo.length > 0) {
  686. if (listTwo[0].packagingMaterialList && listTwo[0].packagingMaterialList.length > 0) {
  687. orderSkuBomList = listTwo[0].packagingMaterialList.map((item) => {
  688. return {
  689. bomSpecId: item.bomSpecId,
  690. unitPrice: item.internalSellingPrice,
  691. quantity: item.quantity,
  692. bomSpecName: item.name,
  693. };
  694. });
  695. }
  696. }
  697. }
  698. let inventoryQuantity = 0;
  699. let getSkuInventoryQuantity = await proxy.post("/skuSpec/getSkuInventoryQuantity", { id: row.id }).then((resQuantity) => {
  700. inventoryQuantity = resQuantity;
  701. });
  702. formData.data.orderSkuList.push({
  703. wlnSkuName: SKU.name,
  704. skuId: row.skuId,
  705. code: row.code,
  706. name: row.name,
  707. skuSpecId: row.id,
  708. bomSpecId: row.bomSpecId,
  709. quantity: undefined,
  710. customProcessingFee: "",
  711. customProcessingType: "",
  712. lssueFee: "",
  713. deliveryMaterialsFee: "",
  714. packingLabor: "",
  715. managementFee: "",
  716. unitPrice: "",
  717. printType: 1,
  718. packageRemark: "",
  719. orderSkuBomList: orderSkuBomList,
  720. blueprint: row.designImgUrl,
  721. productionDocument: row.sharedFolder,
  722. artworkLibraryId: "0",
  723. inventoryQuantity: inventoryQuantity,
  724. });
  725. ElMessage({ message: "添加成功", type: "success" });
  726. };
  727. const rowIndex = ref(null);
  728. const openPackingFittings = ref(false);
  729. const clickPackingFittings = (index) => {
  730. rowIndex.value = index;
  731. openPackingFittings.value = true;
  732. };
  733. const clickDeletePackingFittings = (index, indexTwo) => {
  734. formData.data.orderSkuList[index].orderSkuBomList.splice(indexTwo, 1);
  735. };
  736. const selectPackingFittings = (data) => {
  737. if (formData.data.orderSkuList[rowIndex.value].orderSkuBomList && formData.data.orderSkuList[rowIndex.value].orderSkuBomList.length > 0) {
  738. let list = formData.data.orderSkuList[rowIndex.value].orderSkuBomList.filter((item) => item.bomSpecId === data.id);
  739. if (list && list.length > 0) {
  740. return ElMessage("包材配件已添加");
  741. }
  742. formData.data.orderSkuList[rowIndex.value].orderSkuBomList.push({
  743. bomSpecId: data.id,
  744. unitPrice: data.internalSellingPrice,
  745. quantity: undefined,
  746. bomSpecName: data.name,
  747. });
  748. } else {
  749. formData.data.orderSkuList[rowIndex.value].orderSkuBomList = [
  750. {
  751. bomSpecId: data.id,
  752. unitPrice: data.internalSellingPrice,
  753. quantity: undefined,
  754. bomSpecName: data.name,
  755. },
  756. ];
  757. }
  758. ElMessage({ message: "添加成功", type: "success" });
  759. };
  760. const changeQuantity = (index) => {
  761. if (formData.data.orderSkuList[index].quantity) {
  762. proxy
  763. .post("/orderInfo/getSkuSpecPrice", {
  764. skuSpecId: formData.data.orderSkuList[index].skuSpecId,
  765. quantity: formData.data.orderSkuList[index].quantity,
  766. random: proxy.random(),
  767. })
  768. .then((res) => {
  769. if (formData.data.orderSkuList[index].printType == 2 && res.customProcessingFee) {
  770. formData.data.orderSkuList[index].customProcessingFee = Number(Math.round(res.customProcessingFee * 2 * 100) / 100);
  771. } else {
  772. formData.data.orderSkuList[index].customProcessingFee = res.customProcessingFee;
  773. }
  774. formData.data.orderSkuList[index].customProcessingType = res.customProcessingType;
  775. formData.data.orderSkuList[index].deliveryMaterialsFee = res.deliveryMaterialsFee;
  776. formData.data.orderSkuList[index].lssueFee = res.lssueFee;
  777. formData.data.orderSkuList[index].packingLabor = res.packingLabor;
  778. formData.data.orderSkuList[index].managementFee = res.managementFee;
  779. formData.data.orderSkuList[index].unitPrice = res.unitPrice;
  780. });
  781. }
  782. };
  783. const cellStyleName = ({ column, columnIndex }) => {
  784. if (column.label === "操作" && columnIndex === 4) {
  785. return "vertical-align";
  786. }
  787. };
  788. const uploadData = ref({});
  789. const uploadFile = async (file) => {
  790. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  791. uploadData.value = res.uploadBody;
  792. file.id = res.id;
  793. file.fileName = res.fileName;
  794. file.fileUrl = res.fileUrl;
  795. return true;
  796. };
  797. const handleSuccess = (UploadFile, index) => {
  798. formData.data.orderSkuList[index].productionDocument = UploadFile.raw.fileUrl;
  799. formData.data.orderSkuList[index].artworkLibraryId = "0";
  800. };
  801. const uploadImgData = ref({});
  802. const uploadImgFile = async (file) => {
  803. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  804. uploadImgData.value = res.uploadBody;
  805. file.id = res.id;
  806. file.fileName = res.fileName;
  807. file.fileUrl = res.fileUrl;
  808. return true;
  809. };
  810. const handleImgSuccess = (UploadFile, index) => {
  811. formData.data.orderSkuList[index].blueprint = UploadFile.raw.fileUrl;
  812. formData.data.orderSkuList[index].artworkLibraryId = "0";
  813. };
  814. const computeQuantity = (index, indexSKU) => {
  815. let quantity = 0;
  816. if (formData.data.orderSkuList[index].quantity && formData.data.orderSkuList[index].orderSkuBomList[indexSKU].quantity) {
  817. quantity = Number(
  818. Math.round(formData.data.orderSkuList[index].orderSkuBomList[indexSKU].quantity * formData.data.orderSkuList[index].quantity * 100) / 100
  819. );
  820. }
  821. return quantity;
  822. };
  823. const computeMoney = (index, indexSKU) => {
  824. let money = 0;
  825. if (
  826. formData.data.orderSkuList[index].quantity &&
  827. formData.data.orderSkuList[index].orderSkuBomList[indexSKU].quantity &&
  828. formData.data.orderSkuList[index].orderSkuBomList[indexSKU].unitPrice
  829. ) {
  830. money = Number(
  831. Math.round(
  832. formData.data.orderSkuList[index].orderSkuBomList[indexSKU].quantity *
  833. formData.data.orderSkuList[index].orderSkuBomList[indexSKU].unitPrice *
  834. formData.data.orderSkuList[index].quantity *
  835. 100
  836. ) / 100
  837. );
  838. }
  839. return money;
  840. };
  841. const getSubtotal = (item) => {
  842. let money = 0;
  843. if (item.quantity) {
  844. money = Number(
  845. Math.round(
  846. (item.customProcessingFee + item.deliveryMaterialsFee + item.lssueFee + item.packingLabor + item.managementFee + item.unitPrice) * item.quantity * 100
  847. ) / 100
  848. );
  849. }
  850. return money;
  851. };
  852. const calculatedAmount = (label) => {
  853. let money = 0;
  854. if (formData.data.orderSkuList && formData.data.orderSkuList.length > 0) {
  855. for (let i = 0; i < formData.data.orderSkuList.length; i++) {
  856. if (formData.data.orderSkuList[i].quantity && formData.data.orderSkuList[i][label]) {
  857. money = Number(Math.round((money + formData.data.orderSkuList[i][label] * formData.data.orderSkuList[i].quantity) * 100) / 100);
  858. }
  859. }
  860. }
  861. return money;
  862. };
  863. const calculatedPackagingMaterialCost = () => {
  864. let money = 0;
  865. if (formData.data.orderSkuList && formData.data.orderSkuList.length > 0) {
  866. for (let i = 0; i < formData.data.orderSkuList.length; i++) {
  867. if (formData.data.orderSkuList[i].orderSkuBomList && formData.data.orderSkuList[i].orderSkuBomList.length > 0) {
  868. for (let j = 0; j < formData.data.orderSkuList[i].orderSkuBomList.length; j++) {
  869. if (formData.data.orderSkuList[i].orderSkuBomList[j].quantity && formData.data.orderSkuList[i].orderSkuBomList[j].unitPrice) {
  870. money = Number(
  871. Math.round(
  872. (money +
  873. formData.data.orderSkuList[i].orderSkuBomList[j].quantity *
  874. formData.data.orderSkuList[i].orderSkuBomList[j].unitPrice *
  875. formData.data.orderSkuList[i].quantity) *
  876. 100
  877. ) / 100
  878. );
  879. }
  880. }
  881. }
  882. }
  883. }
  884. return money;
  885. };
  886. const calculatedTotalAmount = () => {
  887. let money = 0;
  888. money = Number(
  889. Math.round(
  890. (calculatedAmount("unitPrice") +
  891. calculatedAmount("customProcessingFee") +
  892. calculatedAmount("lssueFee") +
  893. calculatedAmount("deliveryMaterialsFee") +
  894. calculatedAmount("packingLabor") +
  895. calculatedAmount("managementFee") +
  896. calculatedOuterBoxPackingFee() +
  897. calculatedPackagingMaterialCost()) *
  898. 100
  899. ) / 100
  900. );
  901. return money;
  902. };
  903. const fileList = ref([]);
  904. const uploadFileData = ref({});
  905. const beforeUpload = async (file) => {
  906. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  907. uploadFileData.value = res.uploadBody;
  908. file.id = res.id;
  909. file.fileName = res.fileName;
  910. file.fileUrl = res.fileUrl;
  911. file.uploadState = true;
  912. return true;
  913. };
  914. const onSuccessFile = (any, UploadFile) => {
  915. UploadFile.raw.uploadState = false;
  916. };
  917. const onPreviewFile = (file) => {
  918. window.open(file.raw.fileUrl, "_blank");
  919. };
  920. const uploadAdhesiveData = ref({});
  921. const uploadAdhesiveFile = async (file) => {
  922. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  923. uploadAdhesiveData.value = res.uploadBody;
  924. file.id = res.id;
  925. file.fileName = res.fileName;
  926. file.fileUrl = res.fileUrl;
  927. return true;
  928. };
  929. const handleAdhesiveSuccess = (UploadFile, index) => {
  930. formData.data.orderSkuList[index].selfAdhesiveStickerFile = {
  931. id: UploadFile.raw.id,
  932. fileName: UploadFile.raw.fileName,
  933. fileUrl: UploadFile.raw.fileUrl,
  934. };
  935. };
  936. const getFormData = () => {
  937. return proxy.deepClone(formData.data);
  938. };
  939. const handleSubmit = async (flag) => {
  940. if (flag) {
  941. return true;
  942. } else {
  943. let status = await proxy.$refs.submit.handleSubmit(() => {});
  944. if (status) {
  945. if (formData.data.orderSkuList && formData.data.orderSkuList.length > 0) {
  946. for (let i = 0; i < formData.data.orderSkuList.length; i++) {
  947. if (!formData.data.orderSkuList[i].blueprint) {
  948. ElMessage("请选择设计图");
  949. return false;
  950. }
  951. if (!formData.data.orderSkuList[i].productionDocument) {
  952. ElMessage("请选择生产文件");
  953. return false;
  954. }
  955. let packagingMaterialCost = 0;
  956. if (formData.data.orderSkuList[i].quantity) {
  957. if (formData.data.orderSkuList[i].orderSkuBomList && formData.data.orderSkuList[i].orderSkuBomList.length > 0) {
  958. for (let j = 0; j < formData.data.orderSkuList[i].orderSkuBomList.length; j++) {
  959. if (formData.data.orderSkuList[i].orderSkuBomList[j].quantity && formData.data.orderSkuList[i].orderSkuBomList[j].unitPrice) {
  960. packagingMaterialCost = Number(
  961. Math.round(
  962. (packagingMaterialCost +
  963. formData.data.orderSkuList[i].orderSkuBomList[j].quantity * formData.data.orderSkuList[i].orderSkuBomList[j].unitPrice) *
  964. 100
  965. ) / 100
  966. );
  967. }
  968. }
  969. }
  970. }
  971. formData.data.orderSkuList[i].packagingMaterialCost = packagingMaterialCost;
  972. }
  973. formData.data.productTotalAmount = calculatedAmount("unitPrice");
  974. formData.data.customProcessingFee = calculatedAmount("customProcessingFee");
  975. formData.data.lssueFee = calculatedAmount("lssueFee");
  976. formData.data.deliveryMaterialsFee = calculatedAmount("deliveryMaterialsFee");
  977. formData.data.packingLabor = calculatedAmount("packingLabor");
  978. formData.data.managementFee = calculatedAmount("managementFee");
  979. formData.data.outerBoxPackingFee = calculatedOuterBoxPackingFee();
  980. formData.data.packagingMaterialCost = calculatedPackagingMaterialCost();
  981. formData.data.totalAmount = calculatedTotalAmount();
  982. if (fileList.value && fileList.value.length > 0) {
  983. for (let i = 0; i < fileList.value.length; i++) {
  984. if (fileList.value[i].raw.uploadState) {
  985. ElMessage("文件上传中,请稍后提交");
  986. return false;
  987. }
  988. }
  989. formData.data.fileList = fileList.value.map((item) => {
  990. return {
  991. id: item.raw.id,
  992. fileName: item.raw.fileName,
  993. fileUrl: item.raw.fileUrl,
  994. };
  995. });
  996. } else {
  997. formData.data.fileList = [];
  998. }
  999. } else {
  1000. return ElMessage("请添加产品");
  1001. }
  1002. return true;
  1003. } else {
  1004. setTimeout(() => {
  1005. const errorDiv = document.getElementsByClassName("is-error");
  1006. errorDiv[0].scrollIntoView();
  1007. }, 0);
  1008. }
  1009. return false;
  1010. }
  1011. };
  1012. watch(
  1013. () => props.queryData,
  1014. (newValue) => {
  1015. formOption.disabled = judgeStatus();
  1016. if (props.queryData && ["10", "20", "30", "40"].includes(route.query.processType)) {
  1017. formData.data = proxy.deepClone(newValue);
  1018. if (route.query.id) {
  1019. proxy.$refs.editor.changeHtml(formData.data.remark);
  1020. }
  1021. let list = [formData.data.id];
  1022. if (formData.data.orderSkuList && formData.data.orderSkuList.length > 0) {
  1023. list = list.concat(formData.data.orderSkuList.map((item) => item.id));
  1024. proxy.post("/fileInfo/getList", { businessIdList: list }).then((fileObj) => {
  1025. if (fileObj[formData.data.id] && fileObj[formData.data.id].length > 0) {
  1026. let file = fileObj[formData.data.id].filter((item) => item.businessType == "0");
  1027. if (file && file.length > 0) {
  1028. fileList.value = file.map((item) => {
  1029. return {
  1030. raw: item,
  1031. name: item.fileName,
  1032. url: item.fileUrl,
  1033. };
  1034. });
  1035. } else {
  1036. fileList.value = [];
  1037. }
  1038. let outerBoxSelfAdhesiveStickerFile = fileObj[formData.data.id].filter((item) => item.businessType == "1");
  1039. if (outerBoxSelfAdhesiveStickerFile && outerBoxSelfAdhesiveStickerFile.length > 0) {
  1040. formData.data.outerBoxSelfAdhesiveStickerFile = outerBoxSelfAdhesiveStickerFile[0];
  1041. } else {
  1042. formData.data.outerBoxSelfAdhesiveStickerFile = {};
  1043. }
  1044. }
  1045. for (let i = 0; i < formData.data.orderSkuList.length; i++) {
  1046. if (fileObj[formData.data.orderSkuList[i].id] && fileObj[formData.data.orderSkuList[i].id].length > 0) {
  1047. formData.data.orderSkuList[i].selfAdhesiveStickerFile = {
  1048. id: fileObj[formData.data.orderSkuList[i].id][0].id,
  1049. fileName: fileObj[formData.data.orderSkuList[i].id][0].fileName,
  1050. fileUrl: fileObj[formData.data.orderSkuList[i].id][0].fileUrl,
  1051. };
  1052. }
  1053. }
  1054. });
  1055. }
  1056. }
  1057. },
  1058. {
  1059. deep: true,
  1060. }
  1061. );
  1062. const saveShippingPackage = (data) => {
  1063. formData.data.orderPackageBomList = data.orderPackageBomList;
  1064. formData.data.outerBoxSelfAdhesiveStickerFile = data.outerBoxSelfAdhesiveStickerFile;
  1065. };
  1066. const calculatedOuterBoxPackingFee = () => {
  1067. let money = 0;
  1068. if (formData.data.orderPackageBomList && formData.data.orderPackageBomList.length > 0) {
  1069. for (let i = 0; i < formData.data.orderPackageBomList.length; i++) {
  1070. if (formData.data.orderPackageBomList[i].internalSellingPrice && formData.data.orderPackageBomList[i].quantity) {
  1071. money = Number(
  1072. Math.round((money + formData.data.orderPackageBomList[i].internalSellingPrice * formData.data.orderPackageBomList[i].quantity) * 100) / 100
  1073. );
  1074. }
  1075. }
  1076. }
  1077. return money;
  1078. };
  1079. // 向父组件暴露
  1080. defineExpose({ getFormData, handleSubmit, saveShippingPackage });
  1081. </script>
  1082. <style lang="scss" scoped>
  1083. ::v-deep(.el-input-number .el-input__inner) {
  1084. text-align: left;
  1085. }
  1086. :deep(.el-dialog) {
  1087. margin-top: 10px !important;
  1088. margin-bottom: 10px !important;
  1089. }
  1090. :deep(.ql-editor) {
  1091. height: auto;
  1092. }
  1093. :deep(.el-table__cell) {
  1094. vertical-align: top;
  1095. }
  1096. :deep(.vertical-align) {
  1097. vertical-align: middle;
  1098. }
  1099. </style>