edit.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. <template>
  2. <div class="component-edit-indent">
  3. <el-dialog
  4. v-model="show"
  5. class="custom-edit-indent-dialog"
  6. :title="
  7. visible === 1
  8. ? $t(prefix_edit + 'title_add')
  9. : $t(prefix_edit + 'title_edit')
  10. "
  11. :close-on-click-modal="false"
  12. :close-on-press-escape="false"
  13. :before-close="close"
  14. width="960px"
  15. >
  16. <el-form
  17. ref="indentForm"
  18. :rules="rules"
  19. :model="form"
  20. label-width="130px"
  21. >
  22. <div class="edit-indent-form flex flex-wrap items-center">
  23. <el-form-item
  24. :label="$t(prefix + 'label_customer_name')"
  25. prop="custom_name"
  26. >
  27. <el-select
  28. v-model="form.custom_name"
  29. style="width: 100%"
  30. :placeholder="$t('text_please_select')"
  31. :remote-method="getCustomListFun"
  32. :loading="loading"
  33. allow-create
  34. remote
  35. filterable
  36. @change="customChange"
  37. >
  38. <el-option
  39. v-for="option in customList"
  40. :key="option.id"
  41. :label="option.name"
  42. :value="option.name"
  43. ></el-option>
  44. </el-select>
  45. </el-form-item>
  46. <el-form-item :label="$t(prefix + 'label_project_name')">
  47. <el-input v-model="form.deal_name"></el-input>
  48. </el-form-item>
  49. <el-form-item
  50. label="SKU"
  51. style="height: 40px"
  52. >
  53. <!-- <el-input
  54. style="display: none"
  55. v-model="form.product_sku"></el-input> -->
  56. <div
  57. class="el-input el-input__wrapper el-input__inner fake-sku-input"
  58. @click="skuSelectVisible = true"
  59. >
  60. {{ form.product_sku }}
  61. </div>
  62. </el-form-item>
  63. <el-form-item
  64. :label="$t(prefix + 'label_product_name')"
  65. prop="product_name"
  66. >
  67. <el-input
  68. v-model="form.product_name"
  69. disabled
  70. ></el-input>
  71. </el-form-item>
  72. <el-form-item
  73. :label="$t(prefix + 'label_require_material')"
  74. prop="require_material"
  75. >
  76. <div
  77. class="flex justify-between items-center"
  78. style="width: 100%"
  79. >
  80. <el-select v-model="form.require_material">
  81. <el-option
  82. v-for="item in materialOptions"
  83. :key="item.value"
  84. :label="item.label"
  85. :value="item.value"
  86. ></el-option>
  87. </el-select>
  88. <el-input
  89. v-if="form.require_material === '其它'"
  90. v-model.trim="form.require_material_other"
  91. placeholder="选其它时必填"
  92. style="width: 45%"
  93. ></el-input>
  94. </div>
  95. </el-form-item>
  96. <el-form-item
  97. :label="$t(prefix + 'label_category')"
  98. prop="product_category"
  99. >
  100. <div
  101. class="flex justify-between items-center"
  102. style="width: 100%"
  103. >
  104. <el-select v-model="form.product_category">
  105. <el-option
  106. v-for="item in categoryOptions"
  107. :key="item.value"
  108. :label="item.label"
  109. :value="item.value"
  110. ></el-option>
  111. </el-select>
  112. <el-input
  113. v-if="form.product_category === '其它'"
  114. v-model.trim="form.product_category_other"
  115. placeholder="选其它时必填"
  116. style="width: 45%"
  117. ></el-input>
  118. </div>
  119. </el-form-item>
  120. <el-form-item
  121. :label="$t(prefix + 'label_print_method')"
  122. prop="print_method"
  123. >
  124. <div
  125. class="flex justify-between items-center"
  126. style="width: 100%"
  127. >
  128. <el-select v-model="form.print_method">
  129. <el-option
  130. v-for="item in printOptions"
  131. :key="item.value"
  132. :label="item.label"
  133. :value="item.value"
  134. ></el-option>
  135. </el-select>
  136. <el-input
  137. v-if="form.print_method === '其它'"
  138. v-model.trim="form.print_method_other"
  139. placeholder="选其它时必填"
  140. style="width: 45%"
  141. ></el-input>
  142. </div>
  143. </el-form-item>
  144. <el-form-item :label="$t(prefix_edit + 'label_print_require')">
  145. <el-input v-model="form.require_print"></el-input>
  146. </el-form-item>
  147. <el-form-item
  148. :label="$t(prefix_edit + 'label_number')"
  149. prop="require_amount"
  150. >
  151. <el-input v-model="form.require_amount"></el-input>
  152. </el-form-item>
  153. <el-form-item :label="$t(prefix_edit + 'label_deliver_date')">
  154. <el-date-picker
  155. v-model="form.due_date"
  156. value-format="yyyy-MM-dd"
  157. type="date"
  158. placeholder="选择日期"
  159. ></el-date-picker>
  160. </el-form-item>
  161. <el-form-item :label="$t(prefix_edit + 'label_ref_dimension')">
  162. <el-input
  163. v-model="form.ref_size_length"
  164. style="width: 50px"
  165. placeholder="长"
  166. ></el-input>
  167. <span>&nbsp;*&nbsp;</span>
  168. <el-input
  169. v-model="form.ref_size_width"
  170. style="width: 50px"
  171. placeholder="宽"
  172. ></el-input>
  173. <span>&nbsp;*&nbsp;</span>
  174. <el-input
  175. v-model="form.ref_size_height"
  176. style="width: 50px"
  177. placeholder="高"
  178. ></el-input>
  179. <span>&nbsp;CM</span>
  180. </el-form-item>
  181. <el-form-item
  182. :label="$t(prefix_edit + 'label_ref_url')"
  183. style="width: 98%"
  184. >
  185. <el-input v-model="form.ref_url"></el-input>
  186. </el-form-item>
  187. <el-form-item
  188. :label="$t(prefix_edit + 'label_comment')"
  189. style="width: 98%"
  190. >
  191. <el-input
  192. v-model="form.other_note"
  193. type="textarea"
  194. :rows="3"
  195. ></el-input>
  196. </el-form-item>
  197. <el-form-item
  198. :label="$t(prefix_edit + 'label_ref_image')"
  199. style="width: 100%"
  200. >
  201. <image-upload
  202. v-model:list="imageList"
  203. :disable-preview="true"
  204. ></image-upload>
  205. </el-form-item>
  206. <el-form-item style="width: 100%">
  207. <el-table
  208. v-show="quoteList.length"
  209. :data="quoteList"
  210. border
  211. stripe
  212. >
  213. <el-table-column
  214. width="200"
  215. :label="$t(prefix_edit + 'col_product_image')"
  216. >
  217. <template #default="scope">
  218. <div v-if="scope.row.product_image.length">
  219. <img
  220. :src="scope.row.product_image[0]"
  221. style="width: 100%; height: auto"
  222. />
  223. </div>
  224. </template>
  225. </el-table-column>
  226. <el-table-column
  227. width="200"
  228. prop="vendor_name"
  229. :label="$t(prefix_edit + 'col_supplier')"
  230. ></el-table-column>
  231. <el-table-column
  232. prop="product_url"
  233. label="URL"
  234. ></el-table-column>
  235. </el-table>
  236. <el-button
  237. type="warning"
  238. size="small"
  239. @click="addInfo"
  240. >
  241. + {{ $t(prefix_edit + 'btn_add_info') }}
  242. </el-button>
  243. </el-form-item>
  244. </div>
  245. </el-form>
  246. <template #footer>
  247. <div class="flex justify-center items-center">
  248. <el-button
  249. size="small"
  250. type="primary"
  251. @click="checkForm(indentForm)"
  252. >
  253. {{ $t('btn_submit') }}
  254. </el-button>
  255. <el-button
  256. size="small"
  257. type="primary"
  258. @click="checkForm(indentForm, false)"
  259. >
  260. {{ $t(prefix_edit + 'btn_submit_and_next') }}
  261. </el-button>
  262. </div>
  263. </template>
  264. </el-dialog>
  265. <editInfo
  266. v-model:visible="infoVisible"
  267. @create="quotaCreated"
  268. ></editInfo>
  269. <sku-select
  270. v-model:visible="skuSelectVisible"
  271. @select="selectSku"
  272. ></sku-select>
  273. </div>
  274. </template>
  275. <script lang="ts" setup>
  276. import { defineComponent, ref, watch, nextTick, inject } from 'vue'
  277. import {
  278. ElButton,
  279. ElForm,
  280. ElFormItem,
  281. ElInput,
  282. ElTable,
  283. ElTableColumn,
  284. ElSelect,
  285. ElOption,
  286. ElDialog,
  287. ElNotification,
  288. ElDatePicker,
  289. } from 'element-plus'
  290. import type { FormInstance } from 'element-plus'
  291. import cloneDeep from 'lodash.clonedeep'
  292. import dayjs from 'dayjs'
  293. import ImageUpload from '@/components/ImageUpload.vue'
  294. import editInfo from './components/info.vue'
  295. import skuSelect from './components/skuSelect.vue'
  296. import { $t } from '@/i18n/index'
  297. import { getCustomList, createIndent } from '@/api/indent'
  298. defineComponent({
  299. name: 'EditIndent',
  300. })
  301. const {
  302. visible = 0,
  303. quotaData = {} as any,
  304. indentData = {} as any,
  305. categoryOptions = [],
  306. printOptions = [],
  307. materialOptions = [],
  308. } = defineProps<{
  309. visible: number
  310. // 引用数据. 没有拼错, 不是quote询价信息列表. 这个数据是‘引用’业务克隆出来的, 虽然最终也会赋值给quoteList
  311. quotaData: object
  312. indentData: object
  313. categoryOptions: any[]
  314. printOptions: any[]
  315. materialOptions: any[]
  316. }>()
  317. watch(
  318. () => visible,
  319. () => {
  320. show.value = visible > 0
  321. if (visible > 0) {
  322. resetData()
  323. }
  324. if (visible === 1 && quotaData?.content?.length) {
  325. quotaCreated(quotaData)
  326. }
  327. if (visible === 2) {
  328. // 编辑. 初始化传进来的数据
  329. const temp = cloneDeep(indentData)
  330. if (temp.due_date) {
  331. temp.due_date = dayjs(temp.due_date * 1000).format('YYYY-MM-DD')
  332. } else {
  333. temp.due_date = ''
  334. }
  335. quoteList.value = cloneDeep(temp.lists || [])
  336. if (Array.isArray(temp.picture) && temp.picture.length) {
  337. nextTick(() => {
  338. imageList.value = temp.picture.map((img: string) => {
  339. return {
  340. url: $mediaRegExp.test(img)
  341. ? img
  342. : import.meta.env.VITE_APP_OSS_PREFIX + img,
  343. }
  344. })
  345. })
  346. }
  347. temp.entity_id = temp.id
  348. delete temp.id
  349. delete temp.admin_id
  350. delete temp.checked
  351. delete temp.create_time
  352. delete temp.creator
  353. delete temp.default_quote
  354. delete temp.list // quoteList
  355. delete temp.update_time
  356. // delete temp.status
  357. form.value = Object.assign({}, cloneDeep(formDemo), temp)
  358. }
  359. },
  360. )
  361. const $emit = defineEmits(['update:visible', 'create'])
  362. const prefix = ref('order.indent.')
  363. const prefix_edit = ref('order.indent_edit.')
  364. const show = ref(false)
  365. const skuSelectVisible = ref(false)
  366. const form = ref({} as any)
  367. const formDemo = {
  368. custom_name: '',
  369. custom_id: '', // 联动custom_name
  370. deal_name: '',
  371. deal_id: '', // 永远是空
  372. product_sku: '',
  373. item_id: '', // 看旧代码是和 product_sku 有联动, 应该是商品的id
  374. product_name: '',
  375. require_material: '',
  376. require_material_other: '',
  377. product_category: '',
  378. product_category_other: '',
  379. print_method: '',
  380. print_method_other: '',
  381. require_print: '',
  382. require_amount: '',
  383. due_date: '',
  384. ref_size_length: '',
  385. ref_size_width: '',
  386. ref_size_height: '',
  387. ref_url: '',
  388. other_note: '',
  389. picture: '',
  390. }
  391. const imageList = ref([])
  392. const checkMaterial = (rule: any, value: any, cb: any) => {
  393. if (value === '') {
  394. return cb(new Error($t('text_please_select')))
  395. } else if (value === '其它') {
  396. if (
  397. !(
  398. form.value.require_material_other &&
  399. form.value.require_material_other.length
  400. )
  401. ) {
  402. return cb(new Error('选择其它时, 需填写具体内容!'))
  403. }
  404. }
  405. cb()
  406. }
  407. const checkCategory = (rule: any, value: any, cb: any) => {
  408. if (value === '') {
  409. return cb(new Error($t('text_please_select')))
  410. } else if (value === '其它') {
  411. if (
  412. !(
  413. form.value.product_category_other &&
  414. form.value.product_category_other.length
  415. )
  416. ) {
  417. return cb(new Error('选择其它时, 需填写具体内容!'))
  418. }
  419. }
  420. cb()
  421. }
  422. const checkPrint = (rule: any, value: any, cb: any) => {
  423. if (value === '') {
  424. return cb(new Error($t('text_please_select')))
  425. } else if (value === '其它') {
  426. if (
  427. !(form.value.print_method_other && form.value.print_method_other.length)
  428. ) {
  429. return cb(new Error('选择其它时, 需填写具体内容!'))
  430. }
  431. }
  432. cb()
  433. }
  434. const rules = {
  435. custom_name: [
  436. {
  437. required: true,
  438. message: $t('text_please_input'),
  439. trigger: 'change',
  440. },
  441. ],
  442. custom_id: [
  443. {
  444. required: true,
  445. message: $t('text_please_input'),
  446. trigger: 'change',
  447. },
  448. ],
  449. product_name: [
  450. {
  451. required: true,
  452. message: '请通过sku表单项选择一个商品',
  453. trigger: 'change',
  454. },
  455. ],
  456. require_material: [
  457. { required: true, validator: checkMaterial, trigger: 'change' },
  458. ],
  459. product_category: [
  460. { required: true, validator: checkCategory, trigger: 'change' },
  461. ],
  462. print_method: [{ required: true, validator: checkPrint, trigger: 'change' }],
  463. require_amount: [
  464. {
  465. required: true,
  466. message: $t('text_please_select'),
  467. trigger: 'change',
  468. },
  469. ],
  470. }
  471. // 客户下拉框候选列表
  472. const customList = ref([] as any[])
  473. const loading = ref(false)
  474. const quoteList = ref([])
  475. const selectSku = (data: any) => {
  476. form.value.product_name = data.product_name || ''
  477. form.value.product_sku = data.product_sku || ''
  478. form.value.item_id = data.id || ''
  479. }
  480. const customChange = (value: any) => {
  481. const temp = customList.value.filter((i: any) => i.name === value)
  482. form.value.custom_id = temp.length ? temp[0].id : ''
  483. }
  484. // 成功创建了报价, 把数据展示到界面
  485. const quotaCreated = (data: any) => {
  486. if (Array.isArray(data.content)) {
  487. quoteList.value = quoteList.value.concat(data.content)
  488. }
  489. }
  490. const resetData = () => {
  491. form.value = cloneDeep(formDemo)
  492. imageList.value = []
  493. customList.value = []
  494. quoteList.value = []
  495. }
  496. const close = (done = {} as any) => {
  497. $emit('update:visible', 0)
  498. if (typeof done === 'function') done()
  499. }
  500. const infoVisible = ref(0)
  501. const addInfo = () => {
  502. infoVisible.value = 1
  503. }
  504. const $mediaRegExp = inject('mediaRegExp') as RegExp
  505. const indentForm = ref<FormInstance>()
  506. const checkForm = (
  507. formEl: FormInstance | undefined,
  508. closeAfterCreate = true,
  509. ) => {
  510. if (!formEl) return
  511. formEl.validate((valid: boolean) => {
  512. if (valid) {
  513. form.value.picture = imageList.value
  514. .map((i: any) => {
  515. return i.url.replace($mediaRegExp, '/')
  516. })
  517. .join(',')
  518. // this$set(
  519. // this.form,
  520. // `quotes`,
  521. // quoteList.value.map((d: any) => d.entity_id || d.id),
  522. // )
  523. form.value.quotes = quoteList.value.map((d: any) => d.entity_id || d.id)
  524. createIndent(form.value)
  525. .then((response: any) => {
  526. // console.log(response, 'create indent')
  527. if (response.code === 1) {
  528. ElNotification({
  529. title: '创建成功',
  530. message: '正在刷新数据',
  531. duration: 3000,
  532. })
  533. // notify parent-component to refresh list data
  534. $emit('create')
  535. resetData()
  536. if (closeAfterCreate) {
  537. close()
  538. } else {
  539. formEl.clearValidate()
  540. }
  541. }
  542. })
  543. .catch(() => {
  544. ElNotification({
  545. duration: 3000,
  546. title: '创建出错',
  547. message:
  548. '请稍后再试. 或者按F12打开控制台, 把错误信息复制出来找管理员排查.',
  549. })
  550. })
  551. }
  552. })
  553. }
  554. const getCustomListFun = (keywords: string) => {
  555. loading.value = true
  556. customList.value = []
  557. getCustomList({ keywords })
  558. .then((response: any) => {
  559. if (Array.isArray(response.result) && response.result.length) {
  560. customList.value = response.result
  561. }
  562. })
  563. .finally(() => {
  564. loading.value = false
  565. })
  566. }
  567. getCustomListFun('')
  568. </script>
  569. <style lang="scss">
  570. .component-edit-indent {
  571. .custom-edit-indent-dialog {
  572. margin-top: 0 !important;
  573. margin-bottom: 0 !important;
  574. height: 100vh;
  575. .el-dialog__body {
  576. max-height: 87vh;
  577. overflow-y: scroll;
  578. overflow-x: auto;
  579. padding-top: 8px;
  580. }
  581. }
  582. }
  583. </style>
  584. <style lang="scss" scoped>
  585. .edit-indent-form {
  586. .el-form-item {
  587. width: 49%;
  588. }
  589. }
  590. .fake-sku-input {
  591. height: 30px;
  592. cursor: pointer;
  593. }
  594. </style>