PurchaseArea.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. <template>
  2. <el-form
  3. class="pd"
  4. ref="dataForm"
  5. v-loading="loading"
  6. :model="dataForm"
  7. :rules="dataFormRules"
  8. label-position="left"
  9. label-width="90px"
  10. >
  11. <el-form-item v-if="formDisabled" label="单据编号" prop="purchaseId">
  12. <el-input disabled :value="dataForm.purchaseId" />
  13. </el-form-item>
  14. <el-row :gutter="20">
  15. <el-col :span="8">
  16. <el-form-item label="网点" prop="websitId">
  17. <el-select v-model="dataForm.websitId" :disabled="formDisabled" placeholder="请选择网点" style="width: 100%">
  18. <el-option v-for="(item, index) in authShop" :key="index" :label="item.name" :value="item.websitId" />
  19. </el-select>
  20. </el-form-item>
  21. </el-col>
  22. <el-col :span="8">
  23. <el-form-item label="供应商" prop="venderId">
  24. <el-select
  25. v-model="dataForm.venderId"
  26. filterable
  27. :disabled="formDisabled"
  28. placeholder="请选择供应商"
  29. style="width: 100%"
  30. >
  31. <el-option
  32. v-for="(item, index) in venderList"
  33. :key="index"
  34. :label="item.venderName"
  35. :value="item.venderId"
  36. :disabled="item.status !== 'ON'"
  37. />
  38. </el-select>
  39. </el-form-item>
  40. </el-col>
  41. <el-col :span="8">
  42. <el-form-item label="采购日期" prop="purchaseTime">
  43. <el-date-picker
  44. v-model="dataForm.purchaseTime"
  45. type="date"
  46. placeholder="选择采购日期"
  47. value-format="yyyy-MM-dd HH:mm:ss"
  48. :disabled="inputParam.openType === 'view'"
  49. style="width: 100%"
  50. />
  51. </el-form-item>
  52. </el-col>
  53. </el-row>
  54. <el-form-item label="采购单图片" prop="image">
  55. <template v-if="inputParam.openType !== 'view'">
  56. <el-upload
  57. v-loading="imageLoading"
  58. element-loading-text="上传中"
  59. element-loading-spinner="el-icon-loading"
  60. element-loading-background="rgba(0, 0, 0, 0.8)"
  61. :disabled="imageLoading"
  62. class="avatar-uploader"
  63. :action="baseURL + 'common/upload'"
  64. :headers="myHeaders"
  65. :show-file-list="false"
  66. :on-success="uploadSuccess"
  67. :before-upload="beforeUpload"
  68. :on-error="uploadError"
  69. >
  70. <img v-if="dataForm.image" :src="$showImgUrl(dataForm.image)" class="avatar" alt="" />
  71. <i v-else class="el-icon-plus avatar-uploader-icon" />
  72. <div slot="tip" class="el-upload__tip" style="margin-top: 0; line-height: 20px">只支持上传jpg/png文件</div>
  73. </el-upload>
  74. </template>
  75. <template v-else>
  76. <el-image
  77. style="width: 100px; height: 100px"
  78. :src="$showImgUrl(dataForm.image)"
  79. :preview-src-list="[$showImgUrl(dataForm.image)]"
  80. />
  81. </template>
  82. </el-form-item>
  83. <el-form-item v-if="dataForm.notes3" label="申请单备注">
  84. <el-input v-model="dataForm.notes3" disabled />
  85. </el-form-item>
  86. <el-form-item v-if="dataForm.notes2" label="供应商备注">
  87. <el-input v-model="dataForm.notes2" disabled />
  88. </el-form-item>
  89. <el-form-item label="备注" prop="notes">
  90. <el-input
  91. v-model="dataForm.notes"
  92. autocomplete="off"
  93. placeholder="备注"
  94. :disabled="inputParam.openType === 'view'"
  95. />
  96. </el-form-item>
  97. <el-row>
  98. <el-col>
  99. <el-divider>采购明细</el-divider>
  100. </el-col>
  101. <el-col>
  102. <el-table
  103. ref="goodsTable"
  104. :data="dataForm.items"
  105. max-height="500"
  106. size="mini"
  107. border
  108. header-cell-class-name="headerRowColor"
  109. show-summary
  110. :summary-method="getSummaries"
  111. class="detail-table"
  112. >
  113. <el-table-column prop="goodsId" label="辅材编号" />
  114. <el-table-column prop="goodsName" label="辅材名称" min-width="180" />
  115. <el-table-column prop="purchaseQty" label="订货数量" header-align="left" align="center" />
  116. <el-table-column prop="deliverQty" label="供应数量" header-align="left" align="center" />
  117. <el-table-column prop="estimateCost" label="预估进价" header-align="left" align="center" />
  118. <el-table-column prop="cost" label="进价" header-align="left" align="center">
  119. <template slot-scope="{ $index, row }">
  120. <label v-if="inputParam.openType === 'view'">{{ row.cost }}</label>
  121. <el-form-item
  122. v-else
  123. style="margin: 18px 0"
  124. label-width="0"
  125. size="mini"
  126. :prop="'items.' + $index + '.cost'"
  127. :rules="dataFormRules.cost"
  128. >
  129. <el-input v-model="row.cost" size="mini" @change="changeCostValue($index, row)" />
  130. </el-form-item>
  131. </template>
  132. </el-table-column>
  133. <el-table-column prop="recQty" label="验收数量" header-align="left" align="center" width="100">
  134. <template slot-scope="{ $index, row }">
  135. <label v-if="inputParam.openType === 'view'">{{ row.recQty + ' /' + row.measureUnit }}</label>
  136. <el-form-item
  137. v-else
  138. style="margin: 18px 0"
  139. label-width="0"
  140. size="mini"
  141. :prop="'items.' + $index + '.recQty'"
  142. :rules="dataFormRules.recQty"
  143. >
  144. <el-input v-model="row.recQty" size="mini" @change="changeCostValue($index, row)">
  145. <template slot="suffix">{{ row.measureUnit }}</template>
  146. </el-input>
  147. </el-form-item>
  148. </template>
  149. </el-table-column>
  150. <el-table-column prop="recGiftQty" label="赠品数量" header-align="left" align="center">
  151. <template slot-scope="{ $index, row }">
  152. <label v-if="inputParam.openType === 'view'">{{ row.recGiftQty + ' /' + row.measureUnit }}</label>
  153. <el-form-item
  154. v-else
  155. style="margin: 18px 0"
  156. label-width="0"
  157. size="mini"
  158. :prop="'items.' + $index + '.recGiftQty'"
  159. :rules="dataFormRules.recGiftQty"
  160. >
  161. <el-input v-model="row.recGiftQty" size="mini">
  162. <template slot="suffix">{{ row.measureUnit }}</template>
  163. </el-input>
  164. </el-form-item>
  165. </template>
  166. </el-table-column>
  167. <el-table-column prop="costValue" label="验收金额" header-align="left" align="center" />
  168. <el-table-column prop="inStockQty" label="入库数量" header-align="left" align="center" width="100">
  169. <template slot-scope="{ $index, row }">
  170. <label>{{ row.inStockQty + ' ' + row.salesUnit }}</label>
  171. </template>
  172. </el-table-column>
  173. <el-table-column prop="inStockCost" label="入库进价" header-align="left" align="center" width="100">
  174. <template slot-scope="{ $index, row }">
  175. <label>{{ row.inStockCost + ' 元/' + row.salesUnit }}</label>
  176. </template>
  177. </el-table-column>
  178. <el-table-column prop="measureUnit" label="采购单位" />
  179. <el-table-column prop="unitQty" label="转换系数" header-align="left" align="center" width="95" />
  180. <el-table-column prop="salesUnit" label="售卖单位" />
  181. <el-table-column prop="productModel" label="商品型号" />
  182. <el-table-column prop="specification" label="规格" />
  183. </el-table>
  184. <el-row>
  185. <el-col :span="24"
  186. ><div>共 {{ goodsTotalCount }} 条记录</div></el-col
  187. >
  188. </el-row>
  189. </el-col>
  190. </el-row>
  191. <div style="text-align: right">
  192. <el-button @click="cancelForm">取 消</el-button>
  193. <el-button
  194. v-if="$restrict('edit') && dataForm.flag === 'SAVE' && dataForm.isRecheck === 'ON'"
  195. type="primary"
  196. :disabled="saveBtn"
  197. @click="submitForm('edit')"
  198. >保 存</el-button
  199. >
  200. <el-button
  201. v-if="$restrict('confirm') && dataForm.flag === 'SUBMIT' && dataForm.isRecheck === 'ON'"
  202. type="success"
  203. @click="confirmSheet(dataForm.purchaseId)"
  204. >审 核</el-button
  205. >
  206. </div>
  207. </el-form>
  208. </template>
  209. <script>
  210. import { computeVal } from '@/api/material-system/common'
  211. import { getToken } from '@/utils/auth'
  212. import { confirmPurchaseSheet, editPurchaseSheet, getPurchaseSheet } from '@/api/material-system/shop/purchase-sheet'
  213. import { listPageV2 } from '@/api/auxiliaryFittings/supplier'
  214. import { getWebsit } from '@/api/customerManagement.js'
  215. export default {
  216. name: 'PurchaseArea',
  217. props: {
  218. inputParam: {
  219. type: Object,
  220. default: function () {
  221. return {
  222. openType: 'add',
  223. purchaseId: ''
  224. }
  225. }
  226. }
  227. },
  228. data() {
  229. const validateCost = (rule, value, callback) => {
  230. this.saveBtn = true
  231. if (Number.isNaN(parseFloat(value))) {
  232. return callback(new Error('请输入数字值'))
  233. }
  234. if (parseFloat(value) < 0) {
  235. return callback(new Error('不能少于0'))
  236. }
  237. this.saveBtn = false
  238. callback()
  239. }
  240. const validateRecQty = (rule, value, callback) => {
  241. this.saveBtn = true
  242. if (Number.isNaN(parseFloat(value))) {
  243. return callback(new Error('请输入数字值'))
  244. }
  245. if (parseFloat(value) < 0) {
  246. return callback(new Error('不能少于0'))
  247. }
  248. this.saveBtn = false
  249. callback()
  250. }
  251. const validateRecGiftQty = (rule, value, callback) => {
  252. this.saveBtn = true
  253. if (Number.isNaN(parseFloat(value))) {
  254. return callback(new Error('请输入数字值'))
  255. }
  256. if (parseFloat(value) < 0) {
  257. return callback(new Error('不能少于0'))
  258. }
  259. this.saveBtn = false
  260. callback()
  261. }
  262. return {
  263. imageLoading: false,
  264. loading: true,
  265. baseURL: process.env.VUE_APP_BASE_API,
  266. myHeaders: { 'x-token': getToken() },
  267. dataForm: {
  268. purchaseId: '', // 单据ID
  269. websitId: '', // 网点ID
  270. websitName: '', // 网点名称
  271. venderId: '', // 供应商ID
  272. venderName: '', // 供应商名称
  273. purchaseTime: '', // 采购日期
  274. image: '',
  275. notes: '', // 备注
  276. flag: '',
  277. items: [] // 关系辅材列表
  278. },
  279. dataFormRules: {
  280. purchaseTime: [{ require: true, message: '请选择采购日期', trigger: 'blur' }],
  281. cost: [{ validator: validateCost, trigger: 'blur' }],
  282. recQty: [{ validator: validateRecQty, trigger: 'blur' }],
  283. recGiftQty: [{ validator: validateRecGiftQty, trigger: 'blur' }]
  284. },
  285. orgDataForm: {},
  286. goodsList: [], // 商品列表
  287. venderList: [], // 供应商列表
  288. innerVisible: false,
  289. searchGoods: '',
  290. saveBtn: false, // 保存按钮状态
  291. authShop: []
  292. }
  293. },
  294. computed: {
  295. formDisabled() {
  296. return this.inputParam.openType === 'view' || this.dataForm.purchaseId !== ''
  297. },
  298. goodsTotalCount: function () {
  299. return this.dataForm && this.dataForm.items ? this.dataForm.items.length : 0
  300. }
  301. },
  302. mounted() {
  303. this.getDetail()
  304. this.getVenderList()
  305. getWebsit({ type: 'C', status: true }).then(res => {
  306. this.authShop = res.data
  307. })
  308. },
  309. methods: {
  310. getDetail(id) {
  311. this.loading = true
  312. const openType = this.inputParam.openType
  313. const purchaseId = id || this.inputParam.purchaseId
  314. if (openType !== 'add') {
  315. getPurchaseSheet({ purchaseId }).then(res => {
  316. this.setDataForm(res.data)
  317. this.loading = false
  318. })
  319. } else {
  320. this.loading = false
  321. }
  322. },
  323. cancelForm() {
  324. this.$emit('getList')
  325. this.$emit('update:isOpen', false)
  326. },
  327. submitForm(type) {
  328. if (this.dataForm.items && this.dataForm.items.length === 0) {
  329. this.$errorMsg('请添加商品后再保存!')
  330. return
  331. }
  332. this.$refs.dataForm.validate(valid => {
  333. if (!this.dataForm.image) {
  334. this.$errorMsg('请添加附件图片')
  335. return
  336. }
  337. if (valid) {
  338. if (type === 'edit') {
  339. editPurchaseSheet(this.dataForm).then(() => {
  340. this.getDetail(this.dataForm.purchaseId)
  341. this.$successMsg('保存成功')
  342. })
  343. }
  344. }
  345. })
  346. },
  347. setDataForm(data) {
  348. this.dataForm = {
  349. purchaseId: data.purchaseId, // 单据编号
  350. websitId: data.websitId, // 网点ID
  351. venderId: data.venderId, // 供应商Id
  352. purchaseTime: data.purchaseTime, // 采购日期
  353. flag: data.flag,
  354. image: data.image,
  355. notes: data.notes, // 备注
  356. items: data.items // 关系商品列表
  357. }
  358. Object.assign(this.orgDataForm, this.dataForm)
  359. },
  360. // 获取供应商列表
  361. getVenderList() {
  362. listPageV2({
  363. pageNum: 1,
  364. pageSize: -1,
  365. params: [
  366. { param: 'a.status', compare: '=', value: 'ON' },
  367. { param: 'a.vender_type', compare: 'like', value: '辅材' }
  368. ]
  369. }).then(res => {
  370. this.venderList = res.data.records
  371. })
  372. },
  373. // 预估进价或申请数量变动
  374. changeCostValue(index, row) {
  375. computeVal({
  376. frontVal: row.applyQty,
  377. afterVal: row.applyCost,
  378. operator: '*',
  379. scale: 2
  380. }).then(res => {
  381. this.dataForm.items[index].applyCostValue = res.data
  382. })
  383. },
  384. getSummaries(param) {
  385. const { columns, data } = param
  386. const sums = []
  387. columns.forEach((column, index) => {
  388. if (index === 0) {
  389. sums[index] = '合计'
  390. return
  391. }
  392. const values = data.map(item => Number(item[column.property]))
  393. if (column.property === 'applyCostValue') {
  394. let count = 0
  395. sums[index] = values.reduce((prev, curr) => {
  396. const suffix = (curr + '').split('.')
  397. if (suffix.length > 1) {
  398. count = suffix[1].length > count ? suffix[1].length : count
  399. }
  400. const value = Number(curr)
  401. if (!isNaN(value)) {
  402. return prev + curr
  403. } else {
  404. return prev
  405. }
  406. }, 0)
  407. sums[index] = parseFloat(sums[index]).toFixed(count)
  408. }
  409. })
  410. return sums
  411. },
  412. // 上传成功回调
  413. uploadSuccess(res) {
  414. this.imageLoading = false
  415. this.dataForm.image = res.data.url
  416. },
  417. // 上传前检查
  418. beforeUpload(file) {
  419. if (this.imageLoading) {
  420. this.$errorMsg('文件上传中,稍后再试!')
  421. return false
  422. }
  423. const fileSuffix = file.name.substring(file.name.lastIndexOf('.') + 1)
  424. const whiteList = ['jpg', 'jpeg', 'png']
  425. if (whiteList.indexOf(fileSuffix) === -1) {
  426. this.$errorMsg('只支持上传jpg/png文件!')
  427. return false
  428. }
  429. this.imageLoading = true
  430. },
  431. uploadError() {
  432. this.imageLoading = false
  433. },
  434. // 审核 采购入库单
  435. confirmSheet(purchaseId) {
  436. this.$confirm(
  437. `此操作将审核 ${purchaseId} 单据,<span style="color: #ff0000;">当前内容如果已修改将忽略保存</span>,是否继续?`,
  438. '提示',
  439. {
  440. confirmButtonText: '确定',
  441. cancelButtonText: '取消',
  442. type: 'warning',
  443. dangerouslyUseHTMLString: true
  444. }
  445. )
  446. .then(() => {
  447. this.loading = true
  448. confirmPurchaseSheet({ purchaseId: purchaseId }).then(
  449. () => {
  450. setTimeout(() => {
  451. this.inputParam.openType = 'view'
  452. this.getDetail(purchaseId)
  453. this.$successMsg('审核成功')
  454. this.loading = false
  455. }, 2000)
  456. },
  457. () => {
  458. this.loading = false
  459. }
  460. )
  461. })
  462. .catch(() => console.log('取消'))
  463. }
  464. }
  465. }
  466. </script>
  467. <style lang="scss" scoped>
  468. .detail-table {
  469. width: 100%;
  470. margin: 15px 0;
  471. ::v-deep .el-input__suffix-inner {
  472. color: red;
  473. }
  474. }
  475. .pd {
  476. padding: 20px 20px 0 20px;
  477. }
  478. </style>