RetailOutModal.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. <template>
  2. <j-modal
  3. :title="title"
  4. :width="width"
  5. :visible="visible"
  6. :confirmLoading="confirmLoading"
  7. :keyboard="false"
  8. :forceRender="true"
  9. v-bind:prefixNo="prefixNo"
  10. fullscreen
  11. switchHelp
  12. switchFullscreen
  13. @cancel="handleCancel"
  14. :id="prefixNo"
  15. style="top: 20px; height: 95%"
  16. >
  17. <template slot="footer">
  18. <a-button @click="handleCancel">取消</a-button>
  19. <a-button v-if="billPrintFlag && isShowPrintBtn" @click="handlePrint('零售出库')">三联打印预览</a-button>
  20. <a-button v-if="checkFlag && isCanCheck" :loading="confirmLoading" @click="handleOkAndCheck">保存并审核</a-button>
  21. <a-button type="primary" :loading="confirmLoading" @click="handleOk">保存(Ctrl+S)</a-button>
  22. <!--发起多级审核-->
  23. <a-button v-if="!checkFlag" @click="handleWorkflow()" type="primary">提交流程</a-button>
  24. </template>
  25. <a-spin :spinning="confirmLoading">
  26. <a-form :form="form">
  27. <a-row class="form-row" :gutter="24">
  28. <a-col :lg="6" :md="12" :sm="24">
  29. <a-form-item
  30. :labelCol="labelCol"
  31. :wrapperCol="wrapperCol"
  32. label="会员卡号"
  33. data-step="1"
  34. data-title="会员卡号"
  35. data-intro="如果发现需要选择的会员卡号尚未录入,可以在下拉框中点击新增会员信息进行录入"
  36. >
  37. <a-select
  38. placeholder="请选择会员卡号"
  39. v-decorator="['organId']"
  40. :dropdownMatchSelectWidth="false"
  41. showSearch
  42. optionFilterProp="children"
  43. @change="onChangeOrgan"
  44. >
  45. <div slot="dropdownRender" slot-scope="menu">
  46. <v-nodes :vnodes="menu" />
  47. <a-divider style="margin: 4px 0" />
  48. <div
  49. v-if="quickBtn.member"
  50. style="padding: 4px 8px; cursor: pointer"
  51. @mousedown="(e) => e.preventDefault()"
  52. @click="addMember"
  53. >
  54. <a-icon type="plus" /> 新增会员
  55. </div>
  56. </div>
  57. <a-select-option v-for="(item, index) in retailList" :key="index" :value="item.id">
  58. {{ item.supplier }}
  59. </a-select-option>
  60. </a-select>
  61. </a-form-item>
  62. </a-col>
  63. <a-col :lg="6" :md="12" :sm="24">
  64. <a-form-item :labelCol="labelCol" :wrapperCol="wrapperCol" label="单据日期">
  65. <j-date v-decorator="['operTime', validatorRules.operTime]" :show-time="true" />
  66. </a-form-item>
  67. </a-col>
  68. <a-col :lg="6" :md="12" :sm="24">
  69. <a-form-item
  70. :labelCol="labelCol"
  71. :wrapperCol="wrapperCol"
  72. label="单据编号"
  73. data-step="2"
  74. data-title="单据编号"
  75. data-intro="单据编号自动生成、自动累加、开头是单据类型的首字母缩写,累加的规则是每次打开页面会自动占用一个新的编号"
  76. >
  77. <a-input placeholder="请输入单据编号" v-decorator.trim="['number']" />
  78. </a-form-item>
  79. </a-col>
  80. <a-col :lg="6" :md="12" :sm="24">
  81. <a-form-item
  82. :labelCol="labelCol"
  83. :wrapperCol="wrapperCol"
  84. label="收款类型"
  85. data-step="3"
  86. data-title="收款类型"
  87. data-intro="收款类型可以有现付和预付款两种类型,当选择了会员之后,如果该会员有预付款,在此处会显示具体预付款的金额,而且系统会优先默认选中预付款"
  88. >
  89. <a-select placeholder="请选择付款类型" v-decorator="['payType']" :dropdownMatchSelectWidth="false">
  90. <a-select-option v-for="(item, index) in payTypeList" :key="index" :value="item.value">
  91. {{ item.text }}
  92. </a-select-option>
  93. </a-select>
  94. </a-form-item>
  95. </a-col>
  96. </a-row>
  97. <a-row class="form-row" :gutter="24">
  98. <a-col :lg="18" :md="12" :sm="24">
  99. <j-editable-table
  100. id="billModal"
  101. :ref="refKeys[0]"
  102. :loading="materialTable.loading"
  103. :columns="materialTable.columns"
  104. :dataSource="materialTable.dataSource"
  105. :minWidth="minWidth"
  106. :maxHeight="300"
  107. :rowNumber="false"
  108. :rowSelection="true"
  109. :actionButton="true"
  110. :dragSortAndNumber="true"
  111. @valueChange="onValueChange"
  112. @added="onAdded"
  113. @deleted="onDeleted"
  114. >
  115. <template #buttonAfter>
  116. <a-row
  117. :gutter="24"
  118. style="float: left"
  119. data-step="4"
  120. data-title="扫码录入"
  121. data-intro="此功能支持扫码枪扫描商品条码进行录入"
  122. >
  123. <a-col v-if="scanStatus" :md="6" :sm="24">
  124. <a-button @click="scanEnter">扫码录入</a-button>
  125. </a-col>
  126. <a-col v-if="!scanStatus" :md="16" :sm="24" style="padding: 0 6px 0 12px">
  127. <a-input
  128. placeholder="请扫条码或序列号并回车"
  129. v-model="scanBarCode"
  130. @pressEnter="scanPressEnter"
  131. ref="scanBarCode"
  132. />
  133. </a-col>
  134. <a-col v-if="!scanStatus" :md="6" :sm="24" style="padding: 0px 18px 0 0">
  135. <a-button @click="stopScan">收起扫码</a-button>
  136. </a-col>
  137. </a-row>
  138. </template>
  139. <template #depotBatchSet>
  140. <a-icon type="down" @click="handleBatchSetDepot" />
  141. </template>
  142. <template #depotAdd>
  143. <a-divider v-if="quickBtn.depot" style="margin: 4px 0" />
  144. <div v-if="quickBtn.depot" style="padding: 4px 8px; cursor: pointer" @click="addDepot">
  145. <a-icon type="plus" /> 新增仓库
  146. </div>
  147. </template>
  148. </j-editable-table>
  149. <a-row class="form-row" :gutter="24">
  150. <a-col :lg="24" :md="24" :sm="24">
  151. <a-form-item :labelCol="labelCol" :wrapperCol="{ xs: { span: 24 }, sm: { span: 24 } }" label="">
  152. <a-textarea :rows="1" placeholder="请输入备注" v-decorator="['remark']" style="margin-top: 8px" />
  153. </a-form-item>
  154. </a-col>
  155. </a-row>
  156. <a-row class="form-row" :gutter="24">
  157. <a-col :lg="6" :md="12" :sm="24">
  158. <a-form-item
  159. :labelCol="labelCol"
  160. :wrapperCol="wrapperCol"
  161. label="附件"
  162. data-step="9"
  163. data-title="附件"
  164. data-intro="可以上传与单据相关的图片、文档,支持多个文件"
  165. >
  166. <j-upload v-model="fileList" bizPath="bill"></j-upload>
  167. </a-form-item>
  168. </a-col>
  169. </a-row>
  170. </a-col>
  171. <div class="sign">
  172. <a-col :lg="6" :md="12" :sm="24">
  173. <a-row class="form-row" :gutter="24">
  174. <a-col :lg="24" :md="6" :sm="6"><br /><br /></a-col>
  175. <a-col :lg="24" :md="6" :sm="6">
  176. <a-form-item
  177. :labelCol="labelCol"
  178. :wrapperCol="wrapperCol"
  179. data-step="5"
  180. data-title="单据金额"
  181. data-intro="单据金额等于左侧商品的总金额"
  182. >
  183. <span slot="label" style="font-size: 20px; line-height: 20px">单据金额</span>
  184. <a-input v-decorator.trim="['changeAmount']" :style="{ color: 'purple' }" :readOnly="true" />
  185. </a-form-item>
  186. </a-col>
  187. <a-col :lg="24" :md="6" :sm="6">
  188. <a-form-item
  189. :labelCol="labelCol"
  190. :wrapperCol="wrapperCol"
  191. data-step="6"
  192. data-title="收款金额"
  193. data-intro="收款金额为收银员收取用户的实际金额"
  194. >
  195. <span slot="label" style="font-size: 20px; line-height: 20px">收款金额</span>
  196. <a-input
  197. v-decorator.trim="['getAmount']"
  198. :style="{ color: 'red' }"
  199. defaultValue="0"
  200. @change="onChangeGetAmount"
  201. />
  202. </a-form-item>
  203. </a-col>
  204. <a-col :lg="24" :md="6" :sm="6">
  205. <a-form-item
  206. :labelCol="labelCol"
  207. :wrapperCol="wrapperCol"
  208. data-step="7"
  209. data-title="找零"
  210. data-intro="找零等于收款金额减去实收金额"
  211. >
  212. <span slot="label" style="font-size: 20px; line-height: 20px">找零</span>
  213. <a-input
  214. v-decorator.trim="['backAmount']"
  215. :style="{ color: 'green' }"
  216. :readOnly="true"
  217. defaultValue="0"
  218. />
  219. </a-form-item>
  220. </a-col>
  221. <a-col :lg="24" :md="6" :sm="6">
  222. <a-form-item
  223. :labelCol="labelCol"
  224. :wrapperCol="wrapperCol"
  225. data-step="8"
  226. data-title="收款账户"
  227. data-intro="收款账户的信息来自基本资料菜单下的【结算账户】"
  228. >
  229. <span slot="label" style="font-size: 20px; line-height: 20px">收款账户</span>
  230. <a-select
  231. placeholder="请选择收款账户"
  232. style="font-size: 20px"
  233. v-decorator="['accountId', validatorRules.accountId]"
  234. :dropdownMatchSelectWidth="false"
  235. >
  236. <div slot="dropdownRender" slot-scope="menu">
  237. <v-nodes :vnodes="menu" />
  238. <a-divider style="margin: 4px 0" />
  239. <div
  240. v-if="quickBtn.account"
  241. style="padding: 4px 8px; cursor: pointer"
  242. @mousedown="(e) => e.preventDefault()"
  243. @click="addAccount"
  244. >
  245. <a-icon type="plus" /> 新增结算账户
  246. </div>
  247. </div>
  248. <a-select-option v-for="(item, index) in accountList" :key="index" :value="item.id">
  249. {{ item.name }}
  250. </a-select-option>
  251. </a-select>
  252. </a-form-item>
  253. </a-col>
  254. </a-row>
  255. </a-col>
  256. </div>
  257. </a-row>
  258. </a-form>
  259. </a-spin>
  260. <member-modal ref="memberModalForm" @ok="memberModalFormOk"></member-modal>
  261. <depot-modal ref="depotModalForm" @ok="depotModalFormOk"></depot-modal>
  262. <account-modal ref="accountModalForm" @ok="accountModalFormOk"></account-modal>
  263. <batch-set-depot ref="batchSetDepotModalForm" @ok="batchSetDepotModalFormOk"></batch-set-depot>
  264. <workflow-iframe ref="modalWorkflow" @ok="workflowModalFormOk"></workflow-iframe>
  265. <bill-print-iframe ref="modalPrint"></bill-print-iframe>
  266. </j-modal>
  267. </template>
  268. <script>
  269. import pick from 'lodash.pick'
  270. import MemberModal from '../../system/modules/MemberModal'
  271. import DepotModal from '../../system/modules/DepotModal'
  272. import AccountModal from '../../system/modules/AccountModal'
  273. import BatchSetDepot from '../dialog/BatchSetDepot'
  274. import WorkflowIframe from '@/components/tools/WorkflowIframe'
  275. import BillPrintIframe from '../dialog/BillPrintIframe'
  276. import { FormTypes } from '@/utils/JEditableTableUtil'
  277. import { JEditableTableMixin } from '@/mixins/JEditableTableMixin'
  278. import { BillModalMixin } from '../mixins/BillModalMixin'
  279. import { getMpListShort, handleIntroJs } from '@/utils/util'
  280. import { getAccount } from '@/api/api'
  281. import { getAction } from '@/api/manage'
  282. import JUpload from '@/components/jeecg/JUpload'
  283. import JDate from '@/components/jeecg/JDate'
  284. import Vue from 'vue'
  285. export default {
  286. name: 'RetailOutModal',
  287. mixins: [JEditableTableMixin, BillModalMixin],
  288. components: {
  289. MemberModal,
  290. DepotModal,
  291. AccountModal,
  292. BatchSetDepot,
  293. WorkflowIframe,
  294. BillPrintIframe,
  295. JUpload,
  296. JDate,
  297. VNodes: {
  298. functional: true,
  299. render: (h, ctx) => ctx.props.vnodes,
  300. },
  301. },
  302. data() {
  303. return {
  304. title: '操作',
  305. width: '1600px',
  306. moreStatus: false,
  307. // 新增时子表默认添加几行空数据
  308. addDefaultRowNum: 1,
  309. visible: false,
  310. operTimeStr: '',
  311. prefixNo: 'LSCK',
  312. fileList: [],
  313. payTypeList: [],
  314. minWidth: 1100,
  315. model: {},
  316. labelCol: {
  317. xs: { span: 24 },
  318. sm: { span: 8 },
  319. },
  320. wrapperCol: {
  321. xs: { span: 24 },
  322. sm: { span: 16 },
  323. },
  324. refKeys: ['materialDataTable'],
  325. activeKey: 'materialDataTable',
  326. materialTable: {
  327. loading: false,
  328. dataSource: [],
  329. columns: [
  330. {
  331. title: '仓库名称',
  332. key: 'depotId',
  333. width: '10%',
  334. type: FormTypes.select,
  335. placeholder: '请选择${title}',
  336. options: [],
  337. allowSearch: true,
  338. validateRules: [{ required: true, message: '${title}不能为空' }],
  339. },
  340. {
  341. title: '条码',
  342. key: 'barCode',
  343. width: '16%',
  344. type: FormTypes.popupJsh,
  345. kind: 'material',
  346. multi: true,
  347. validateRules: [{ required: true, message: '${title}不能为空' }],
  348. },
  349. { title: '名称', key: 'name', width: '12%', type: FormTypes.normal },
  350. { title: '规格', key: 'standard', width: '10%', type: FormTypes.normal },
  351. { title: '型号', key: 'model', width: '10%', type: FormTypes.normal },
  352. { title: '颜色', key: 'color', width: '5%', type: FormTypes.normal },
  353. { title: '品牌', key: 'brand', width: '6%', type: FormTypes.normal },
  354. { title: '制造商', key: 'mfrs', width: '6%', type: FormTypes.normal },
  355. { title: '扩展信息', key: 'materialOther', width: '7%', type: FormTypes.normal },
  356. { title: '库存', key: 'stock', width: '5%', type: FormTypes.normal },
  357. { title: '单位', key: 'unit', width: '5%', type: FormTypes.normal },
  358. { title: '序列号', key: 'snList', width: '12%', type: FormTypes.popupJsh, kind: 'sn', multi: true },
  359. { title: '批号', key: 'batchNumber', width: '8%', type: FormTypes.popupJsh, kind: 'batch', multi: false },
  360. { title: '有效期', key: 'expirationDate', width: '9%', type: FormTypes.input, readonly: true },
  361. { title: '多属性', key: 'sku', width: '9%', type: FormTypes.normal },
  362. {
  363. title: '数量',
  364. key: 'operNumber',
  365. width: '6%',
  366. type: FormTypes.inputNumber,
  367. statistics: true,
  368. validateRules: [{ required: true, message: '${title}不能为空' }],
  369. },
  370. { title: '单价', key: 'unitPrice', width: '6%', type: FormTypes.inputNumber },
  371. { title: '金额', key: 'allPrice', width: '6%', type: FormTypes.inputNumber, statistics: true },
  372. { title: '备注', key: 'remark', width: '7%', type: FormTypes.input },
  373. ],
  374. },
  375. confirmLoading: false,
  376. validatorRules: {
  377. operTime: {
  378. rules: [{ required: true, message: '请输入单据日期!' }],
  379. },
  380. accountId: {
  381. rules: [{ required: true, message: '请选择结算账户!' }],
  382. },
  383. },
  384. url: {
  385. add: '/depotHead/addDepotHeadAndDetail',
  386. edit: '/depotHead/updateDepotHeadAndDetail',
  387. detailList: '/depotItem/getDetailList',
  388. },
  389. }
  390. },
  391. created() {
  392. this.initPayTypeList()
  393. let realScreenWidth = window.screen.width
  394. this.minWidth = realScreenWidth < 1500 ? 800 : 1100
  395. },
  396. methods: {
  397. //调用完edit()方法之后会自动调用此方法
  398. editAfter() {
  399. this.billStatus = '0'
  400. this.changeColumnHide()
  401. this.changeFormTypes(this.materialTable.columns, 'snList', 0)
  402. this.changeFormTypes(this.materialTable.columns, 'batchNumber', 0)
  403. this.changeFormTypes(this.materialTable.columns, 'expirationDate', 0)
  404. if (this.action === 'add') {
  405. this.addInit(this.prefixNo)
  406. this.fileList = []
  407. this.$nextTick(() => {
  408. handleIntroJs(this.prefixNo, 1)
  409. })
  410. this.$nextTick(() => {
  411. this.form.setFieldsValue({ payType: '现付', getAmount: 0, backAmount: 0 })
  412. })
  413. } else {
  414. this.model.operTime = this.model.operTimeStr
  415. if (this.model.backAmount) {
  416. this.model.getAmount = (this.model.changeAmount + this.model.backAmount).toFixed(2)
  417. } else {
  418. this.model.getAmount = this.model.changeAmount
  419. }
  420. this.fileList = this.model.fileName
  421. if (this.model.payType === '预付款') {
  422. this.payTypeList = []
  423. this.payTypeList.push({ value: '预付款', text: '预付款' })
  424. this.payTypeList.push({ value: '现付', text: '现付' })
  425. }
  426. this.$nextTick(() => {
  427. this.form.setFieldsValue(
  428. pick(
  429. this.model,
  430. 'organId',
  431. 'operTime',
  432. 'number',
  433. 'payType',
  434. 'remark',
  435. 'discount',
  436. 'discountMoney',
  437. 'discountLastMoney',
  438. 'otherMoney',
  439. 'accountId',
  440. 'changeAmount',
  441. 'getAmount',
  442. 'backAmount'
  443. )
  444. )
  445. })
  446. // 加载子表数据
  447. let params = {
  448. headerId: this.model.id,
  449. mpList: getMpListShort(Vue.ls.get('materialPropertyList')), //扩展属性
  450. linkType: 'basic',
  451. }
  452. let url = this.readOnly ? this.url.detailList : this.url.detailList
  453. this.requestSubTableData(url, params, this.materialTable)
  454. }
  455. //复制新增单据-初始化单号和日期
  456. if (this.action === 'copyAdd') {
  457. this.model.id = ''
  458. this.model.tenantId = ''
  459. this.copyAddInit(this.prefixNo)
  460. }
  461. this.initSystemConfig()
  462. this.initRetail(0)
  463. this.initDepot()
  464. this.initAccount(0)
  465. this.initPlatform()
  466. this.initQuickBtn()
  467. },
  468. //提交单据时整理成formData
  469. classifyIntoFormData(allValues) {
  470. let totalPrice = 0
  471. let billMain = Object.assign(this.model, allValues.formValue)
  472. let detailArr = allValues.tablesValue[0].values
  473. billMain.type = '出库'
  474. billMain.subType = '零售'
  475. for (let item of detailArr) {
  476. totalPrice += item.allPrice - 0
  477. }
  478. billMain.totalPrice = totalPrice
  479. if (this.fileList && this.fileList.length > 0) {
  480. billMain.fileName = this.fileList
  481. } else {
  482. billMain.fileName = ''
  483. }
  484. if (this.model.id) {
  485. billMain.id = this.model.id
  486. }
  487. billMain.status = this.billStatus
  488. return {
  489. info: JSON.stringify(billMain),
  490. rows: JSON.stringify(detailArr),
  491. }
  492. },
  493. //加载收款类型
  494. initPayTypeList() {
  495. this.payTypeList.push({ value: '现付', text: '现付' })
  496. },
  497. initAccount(isChecked) {
  498. getAccount({}).then((res) => {
  499. if (res && res.code === 200) {
  500. this.accountList = res.data.accountList
  501. if (isChecked && this.accountList.length > 0) {
  502. this.form.setFieldsValue({ accountId: this.accountList[0].id })
  503. }
  504. }
  505. })
  506. },
  507. //选择会员的触发事件
  508. onChangeOrgan(value) {
  509. getAction('/supplier/info', { id: value }).then((res) => {
  510. if (res && res.code === 200) {
  511. this.payTypeList = []
  512. let info = res.data.info
  513. if (info.advanceIn) {
  514. this.payTypeList.push({ value: '预付款', text: '预付款(' + info.advanceIn + ')' })
  515. this.payTypeList.push({ value: '现付', text: '现付' })
  516. this.$nextTick(() => {
  517. this.form.setFieldsValue({ payType: '预付款' })
  518. })
  519. } else {
  520. this.payTypeList.push({ value: '现付', text: '现付' })
  521. }
  522. }
  523. })
  524. },
  525. //改变实收金额、收款金额的值
  526. autoChangePrice(target) {
  527. let allLastMoney = target.statisticsColumns.allPrice
  528. this.$nextTick(() => {
  529. this.form.setFieldsValue({ changeAmount: allLastMoney, getAmount: allLastMoney, backAmount: 0 })
  530. })
  531. },
  532. //改变收款金额
  533. onChangeGetAmount(e) {
  534. const value = e.target.value
  535. let changeAmount = this.form.getFieldValue('changeAmount') - 0
  536. let backAmount = (value - changeAmount).toFixed(2) - 0
  537. this.$nextTick(() => {
  538. this.form.setFieldsValue({ backAmount: backAmount })
  539. })
  540. },
  541. },
  542. }
  543. </script>
  544. <style scoped>
  545. .sign .ant-input {
  546. font-size: 30px;
  547. font-weight: bolder;
  548. text-align: center;
  549. border-left-width: 0px !important;
  550. border-top-width: 0px !important;
  551. border-right-width: 0px !important;
  552. }
  553. </style>