queryPart.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. <template>
  2. <div class="productInfoList-wrap">
  3. <!-- 搜索条件 -->
  4. <div class="table-page-search-wrapper">
  5. <a-form-model
  6. ref="ruleForm"
  7. class="form-model-con"
  8. layout="inline"
  9. :rules="rules"
  10. :model="queryParam"
  11. @keyup.enter.native="$refs.table.refresh(true)" >
  12. <a-row :gutter="5">
  13. <a-col :lg="4" :md="6" :sm="12">
  14. <a-form-model-item label="产品编码">
  15. <a-input id="productInfoList-code" ref="searchProductCode" v-model.trim="queryParam.productCode" allowClear placeholder="请输入产品编码"/>
  16. </a-form-model-item>
  17. </a-col>
  18. <a-col :lg="4" :md="6" :sm="12">
  19. <a-form-model-item label="产品名称">
  20. <a-input id="productInfoList-name" v-model.trim="queryParam.productName" allowClear placeholder="请输入产品名称"/>
  21. </a-form-model-item>
  22. </a-col>
  23. <a-col :lg="4" :md="6" :sm="12">
  24. <a-form-model-item label="原厂编码">
  25. <a-input id="productInfoList-origCode" v-model.trim="queryParam.productOrigCode" allowClear placeholder="请输入原厂编码"/>
  26. </a-form-model-item>
  27. </a-col>
  28. <a-col :lg="4" :md="6" :sm="12">
  29. <a-form-model-item label="产品分类">
  30. <ProductType id="productInfoList-productType" :isDealer="true" @change="changeProductType" v-model="productType"></ProductType>
  31. </a-form-model-item>
  32. </a-col>
  33. <template v-if="advanced">
  34. <a-col :lg="4" :md="6" :sm="12">
  35. <a-form-model-item label="产品品牌">
  36. <ProductBrand id="productInfoList-productBrandSn" v-model="queryParam.brandSn"></ProductBrand>
  37. </a-form-model-item>
  38. </a-col>
  39. <a-col :lg="4" :md="6" :sm="12">
  40. <a-form-model-item label="仓库">
  41. <a-select
  42. placeholder="请选择仓库"
  43. id="productInfoList-warehouseSn"
  44. allowClear
  45. v-model="queryParam.warehouseSn"
  46. :showSearch="true"
  47. option-filter-prop="children"
  48. :filter-option="filterOption">
  49. <a-select-option v-for="item in warehouseList" :key="item.warehouseSn" :value="item.warehouseSn">{{ item.name }}</a-select-option>
  50. </a-select>
  51. </a-form-model-item>
  52. </a-col>
  53. <a-col :lg="6" :md="8" :sm="12" v-if="$hasPermissions('B_salerVinFindProduct')">
  54. <a-form-model-item label="车架号(VIN)" prop="vinCode">
  55. <a-input id="productInfoList-vinCode" v-model.trim="queryParam.vinCode" allowClear placeholder="请输入车架号(VIN)">
  56. <a-icon @click="uploadFun" :type="vinLoading?'loading':'camera'" slot="addonAfter" :style="{ fontSize: '18px', verticalAlign: 'bottom' }" />
  57. </a-input>
  58. <input type="file" id="filed" accept="image/jpeg,image/png" hidden="" @change="filePreview">
  59. </a-form-model-item>
  60. </a-col>
  61. </template>
  62. <a-col :lg="3" :md="8" :sm="12" style="margin-bottom: 10px;">
  63. <a-button type="primary" @click="$refs.table.refresh(true)" :disabled="disabled" id="productInfoList-refresh">查询</a-button>
  64. <a-button style="margin-left: 5px" @click="resetSearchForm" id="productInfoList-reset">重置</a-button>
  65. <a @click="advanced=!advanced" style="margin:0 0 0 10px">
  66. {{ advanced ? '收起' : '展开' }}
  67. <a-icon :type="advanced ? 'up' : 'down'"/>
  68. </a>
  69. </a-col>
  70. <a-col :lg="5" :md="8" :sm="12" style="margin-top: 6px;">
  71. <a-checkbox v-model="cost" v-if="$hasPermissions('M_ShowAllCost')" id="salesQuery-cost">成本价</a-checkbox>
  72. <a-checkbox v-model="cityPrice" id="salesQuery-cityPrice">市级价</a-checkbox>
  73. <a-checkbox v-model="tyuePrice" v-if="$store.state.user.isShowSpecialPrice==1" id="salesQuery-tyuePrice">特约价</a-checkbox>
  74. <a-checkbox v-model="zdPrice" id="salesQuery-zdPrice">终端价</a-checkbox>
  75. </a-col>
  76. </a-row>
  77. </a-form-model>
  78. </div>
  79. <a-alert type="error" style="margin-bottom: 10px;" v-if="vinInfoData&&!vinInfoData.vinInfo">
  80. <template slot="message"><a-icon type="exclamation-circle" theme="filled" :style="{ color: '#E70012', fontSize: '15px', verticalAlign: 'sub', marginRight: '3px' }" />抱歉!暂未找到匹配VIN码的车型!</template>
  81. </a-alert>
  82. <a-alert type="warning" style="margin-bottom: 10px;cursor: pointer;" v-if="vinInfoData&&vinInfoData.vinInfo" @click="openCarInfoModal=true">
  83. <template slot="message">
  84. <div style="display: flex;justify-content: space-between;align-items: center;" @click="openCarInfoModal=true">
  85. <div>
  86. <img :src="vinInfoData.vinInfo && vinInfoData.vinInfo.icon?(vinInfoData.vinInfo.icon+'?x-oss-process=image/resize,h_30,m_lfit'):defImg" width="30" height="30" class="imageUrl" style="border-radius: 50%;vertical-align: middle;margin-right: 3px;" />
  87. <span style="vertical-align: middle;">{{ vinInfoData.vinInfo.text }}</span>
  88. </div>
  89. <div style="color: #f90;">
  90. <span>查看更多</span> >
  91. </div>
  92. </div>
  93. </template>
  94. </a-alert>
  95. <!-- 列表 -->
  96. <s-table
  97. class="sTable"
  98. ref="table"
  99. size="small"
  100. :rowKey="(record) => record.no"
  101. rowKeyName="no"
  102. :columns="columns"
  103. :data="loadData"
  104. :customRow="handleClickRow"
  105. :defaultLoadData="false"
  106. :pageSize="10"
  107. :scroll="{ y: 149 }"
  108. bordered>
  109. <div slot="costTitle">
  110. <a-tooltip placement="top">
  111. <template slot="title">
  112. 产品所在仓库仓位的最近一次入库成本,不包含盘盈入库和仓库调拨入库。
  113. </template>
  114. <span style="margin-right: 5px;">参考成本价</span> <a-icon type="question-circle" />
  115. </a-tooltip>
  116. </div>
  117. <!-- 售价 -->
  118. <template slot="salePrice" slot-scope="text, record">
  119. <div style="display: flex;align-items: center;" @dblclick.stop>
  120. <a-input-number
  121. size="small"
  122. v-model="record.price"
  123. :precision="2"
  124. :min="0"
  125. :max="999999"
  126. style="width: 100%;"
  127. placeholder="请输入" />
  128. <span style="color: red;margin: 0 2px;font-size: 14px;" v-if="record.origSalePriceFlag == 1">原</span>
  129. <span v-else>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
  130. </div>
  131. </template>
  132. <!-- 销售数量 -->
  133. <template slot="nums" slot-scope="text, record">
  134. <div @dblclick.stop>
  135. <a-input-number
  136. size="small"
  137. v-model="record.salesNums"
  138. :precision="0"
  139. :min="0"
  140. :max="999999"
  141. style="width: 100%;"
  142. placeholder="请输入" />
  143. </div>
  144. </template>
  145. <!-- 操作 -->
  146. <template slot="action" slot-scope="text, record">
  147. <a-button
  148. size="small"
  149. type="link"
  150. class="button-primary"
  151. @click.stop="handleAdd(record)"
  152. id="productInfoList-edit-btn">添加</a-button>
  153. <a-button
  154. size="small"
  155. type="link"
  156. class="button-primary"
  157. @click.stop="handleDetail(record)"
  158. id="productInfoList-detail-btn"
  159. style="margin-left: 5px;">销售记录</a-button>
  160. </template>
  161. </s-table>
  162. <!-- 销售记录 -->
  163. <product-salesRecord-modal ref="salseRecord" :openModal="openModal" @close="closeModal" />
  164. <!-- 查看车辆信息 -->
  165. <car-info-modal ref="carInfoModal" :openModal="openCarInfoModal" :infoData="vinInfoData&&vinInfoData.vinInfo" @close="openCarInfoModal=false" />
  166. </div>
  167. </template>
  168. <script>
  169. import { querySumByProductLocation } from '@/api/stock'
  170. import { warehouseAllList } from '@/api/warehouse'
  171. import productSalesRecordModal from './productSalesRecordModal.vue'
  172. import carInfoModal from './carInfoModal.vue'
  173. import ProductType from '../../common/productType.js'
  174. import ProductBrand from '../../common/productBrand.js'
  175. import { STable, VSelect, Upload } from '@/components'
  176. import { supperCodeByVin, vinCodeParse } from '@/api/sales'
  177. import defImg from '@/assets/def_img@2x.png'
  178. export default {
  179. name: 'QueryPart',
  180. components: { STable, VSelect, Upload, productSalesRecordModal, carInfoModal, ProductType, ProductBrand },
  181. props: {
  182. newLoading: Boolean
  183. },
  184. data () {
  185. return {
  186. advanced: false, // 高级搜索 展开/关闭
  187. vinLoading: false,
  188. productType: [],
  189. defImg,
  190. queryParam: { // 查询条件
  191. customerSn: '',
  192. salesBillSn: '',
  193. salePriceType: '',
  194. productCode: '', // 产品编码
  195. productName: '', // 产品名称
  196. productOrigCode: '', // 原厂编码
  197. vinCode: '',
  198. productCodeList: undefined, // 车架号
  199. brandSn: undefined, // 产品品牌
  200. productTypeSn1: '', // 产品一级分类
  201. productTypeSn2: '', // 产品二级分类
  202. productTypeSn3: '', // 产品三级分类
  203. warehouseSn: undefined, // 仓库、
  204. enableFlag: '1'
  205. },
  206. priceType: '',
  207. buyerSn: '',
  208. rules: {
  209. vinCode: [ { len: 17, message: '请输入正确的车架号(VIN)', trigger: 'change' } ]
  210. },
  211. disabled: false, // 查询、重置按钮是否可操作
  212. warehouseList: [], // 仓库列表
  213. vinInfoData: null,
  214. // 加载数据方法 必须为 Promise 对象
  215. loadData: parameter => {
  216. const _this = this
  217. _this.queryParam.salePriceType = _this.priceType
  218. _this.queryParam.customerSn = _this.buyerSn
  219. // 排序
  220. if (parameter.sortField == 'productCode') {
  221. parameter.sortField = 'code'
  222. parameter.sortAlias = 'product '
  223. }
  224. if (parameter.sortField == 'brandName') {
  225. parameter.sortField = 'firstChar'
  226. parameter.sortAlias = 'brand'
  227. }
  228. if (parameter.sortField == 'warehouseName') {
  229. parameter.sortField = 'warehouseSn'
  230. parameter.sortAlias = 'sd'
  231. }
  232. const params = Object.assign(parameter, _this.queryParam)
  233. if (_this.queryParam.vinCode && _this.queryParam.vinCode.length == 17 && !this.onlyList) { // 输入vin,查出vin码信息后请求列表数据
  234. _this.disabled = true
  235. return supperCodeByVin({ vin: _this.queryParam.vinCode }).then(res => {
  236. if (res.status == 200) {
  237. _this.vinInfoData = res.data
  238. params.productCodeList = res.data.partCodeList || []
  239. return _this.getList(params)
  240. } else {
  241. _this.vinInfoData = null
  242. _this.$refs.table.localLoading = false
  243. _this.$refs.table.clearTable()
  244. }
  245. })
  246. } else if (_this.queryParam.vinCode && _this.queryParam.vinCode.length < 17 && !this.onlyList) { // 输入vin,但vin码不符合标准,不查vin码信息,不请求列表数据
  247. _this.$refs.table.localLoading = false
  248. _this.$refs.table.clearTable()
  249. } else if (this.onlyList) {
  250. _this.disabled = true
  251. if (_this.queryParam.vinCode && _this.vinInfoData) {
  252. return _this.getList(Object.assign(params, { productCodeList: _this.vinInfoData.partCodeList }))
  253. } else {
  254. return _this.getList(params)
  255. }
  256. } else { // 未输入vin码信息,只查列表数据
  257. _this.disabled = true
  258. return _this.getList(params)
  259. }
  260. },
  261. openModal: false, // 查看客户详情 弹框
  262. cost: false, // 成本价
  263. cityPrice: false, // 城市价
  264. tyuePrice: false, // 特约价
  265. zdPrice: false, // 终端价
  266. openCarInfoModal: false,
  267. onlyList: false
  268. }
  269. },
  270. computed: {
  271. columns () {
  272. const arr = [
  273. { title: '产品编码', dataIndex: 'productCode', width: '15%', align: 'center', sorter: true, customRender: function (text) { return text || '--' } },
  274. { title: '产品名称', dataIndex: 'productName', width: '18%', align: 'center', customRender: function (text) { return text || '--' }, ellipsis: true },
  275. { title: '原厂编码', dataIndex: 'productOrigCode', width: '10%', align: 'center', customRender: function (text) { return text || '--' } },
  276. { title: '品牌', dataIndex: 'brandName', width: '11%', align: 'center', sorter: true, customRender: function (text) { return text || '--' } },
  277. { title: '仓库', dataIndex: 'warehouseName', width: '8%', align: 'center', customRender: function (text) { return text || '--' } },
  278. { title: '仓位', dataIndex: 'warehouseLocationName', width: '8%', align: 'center', customRender: function (text) { return text || '--' } }
  279. ]
  280. if (this.cost) {
  281. arr.push({ slots: { title: 'costTitle' }, dataIndex: 'putCost', width: '8%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } })
  282. }
  283. if (this.cityPrice) {
  284. arr.push({ title: '市级价', dataIndex: 'dealerProduct.cityPrice', width: '5%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } })
  285. }
  286. if (this.tyuePrice) {
  287. arr.push({ title: '特约价', dataIndex: 'dealerProduct.specialPrice', width: '5%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } })
  288. }
  289. if (this.zdPrice) {
  290. arr.push({ title: '终端价', dataIndex: 'dealerProduct.terminalPrice', width: '5%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } })
  291. }
  292. return arr.concat([
  293. { title: '单位', dataIndex: 'unit', width: '4%', align: 'center', customRender: function (text) { return text || '--' } },
  294. { title: '售价', dataIndex: 'salePrice', scopedSlots: { customRender: 'salePrice' }, width: '7%', align: 'center' },
  295. { title: '销售数量', dataIndex: 'salesNums', scopedSlots: { customRender: 'nums' }, width: '6%', align: 'center' },
  296. { title: '库存数量', dataIndex: 'currentQty', width: '6%', align: 'center', customRender: function (text) { return ((text || text == 0) ? text : '--') } },
  297. { title: '操作', dataIndex: 'action', scopedSlots: { customRender: 'action' }, width: '10%', align: 'center' }
  298. ])
  299. }
  300. },
  301. created () {
  302. // 仓库
  303. if (this.warehouseList.length == 0) {
  304. this.getWarehouse()
  305. }
  306. },
  307. methods: {
  308. getList (params) {
  309. const _this = this
  310. return querySumByProductLocation(params).then(res => {
  311. let data
  312. this.onlyList = false
  313. if (res.status == 200) {
  314. data = res.data
  315. data.list = data.list.filter(item => item != null)
  316. const no = (data.pageNo - 1) * data.pageSize
  317. for (var i = 0; i < data.list.length; i++) {
  318. data.list[i].no = data.list[i].productSn + '-' + (no + i + 1)
  319. data.list[i].salesNums = 1
  320. data.list[i].currentQty = data.list[i].currentQty || 0
  321. data.list[i].price = data.list[i].lastSalePrice ? data.list[i].lastSalePrice : data.list[i].salePrice
  322. data.list[i].productOrigCode = data.list[i].productOrigCode ? data.list[i].productOrigCode.trim() : ''
  323. }
  324. if (!params.vinCode) {
  325. _this.vinInfoData = null
  326. }
  327. } else {
  328. data = {
  329. list: [],
  330. pageNo: 1,
  331. pageSize: 10
  332. }
  333. }
  334. _this.disabled = false
  335. console.log(data)
  336. return data
  337. })
  338. },
  339. // vin change
  340. vinCodeChange (e) {
  341. if (e.target.value.length == 17) {
  342. supperCodeByVin({ vin: e.target.value }).then(res => {
  343. if (res.status == 200) {
  344. this.queryParam.productCodeList = res.data
  345. } else {
  346. this.queryParam.productCodeList = undefined
  347. }
  348. })
  349. } else {
  350. this.queryParam.productCodeList = undefined
  351. }
  352. },
  353. // 双击列表
  354. handleClickRow (record) {
  355. const _this = this
  356. return {
  357. on: {
  358. dblclick: (event) => {
  359. event.stopPropagation()
  360. _this.$emit('add', record)
  361. }
  362. }
  363. }
  364. },
  365. // 重置
  366. resetSearchForm () {
  367. this.queryParam.productCode = ''
  368. this.queryParam.productName = ''
  369. this.queryParam.productOrigCode = ''
  370. this.queryParam.brandSn = undefined
  371. this.queryParam.productTypeSn1 = ''
  372. this.queryParam.productTypeSn2 = ''
  373. this.queryParam.productTypeSn3 = ''
  374. this.queryParam.warehouseSn = undefined
  375. this.queryParam.productCodeList = undefined
  376. this.queryParam.vinCode = ''
  377. this.productType = []
  378. this.$refs.ruleForm.resetFields()
  379. this.$refs.table.refresh(true)
  380. this.vinInfoData = null
  381. },
  382. pageInit (buyerSn, priceType, salesBillSn) {
  383. this.priceType = priceType || ''
  384. this.buyerSn = buyerSn || ''
  385. this.queryParam.salesBillSn = salesBillSn || ''
  386. if (this.onlyList) { // 不清空查询条件
  387. this.$refs.table.refresh()
  388. } else {
  389. this.resetSearchForm()
  390. }
  391. this.$refs.searchProductCode.focus()
  392. },
  393. // 刷新当前页面
  394. resetCurForm () {
  395. this.$refs.table.refresh()
  396. },
  397. // 清空数据
  398. clearTable () {
  399. this.vinInfoData = null
  400. this.$refs.ruleForm.resetFields()
  401. this.$refs.table.clearTable()
  402. },
  403. filterOption (input, option) {
  404. return (
  405. option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
  406. )
  407. },
  408. // 选择配件
  409. handleAdd (row) {
  410. const _this = this
  411. console.log(row.price, row.lastSalePrice, row.salePrice, row.lastSalePrice < row.salePrice)
  412. if (row.lastSalePrice && (row.price < row.salePrice)) {
  413. _this.$confirm({
  414. title: '提示',
  415. content: '售价低于定价,是否仍继续添加?',
  416. centered: true,
  417. closable: true,
  418. onOk () {
  419. _this.$emit('add', row)
  420. }
  421. })
  422. } else {
  423. _this.$emit('add', row)
  424. }
  425. },
  426. // 销售记录
  427. handleDetail (row) {
  428. this.openModal = true
  429. this.$refs.salseRecord.getDetail(this.buyerSn, row.productSn, row)
  430. },
  431. // 关闭弹框
  432. closeModal () {
  433. this.openModal = false
  434. },
  435. uploadFun () {
  436. document.getElementById('filed').click()
  437. },
  438. filePreview (e) {
  439. const _this = this
  440. var files = e.target.files[0]
  441. const formData = new FormData()
  442. formData.append('savePathType', 'local')
  443. formData.append('file', files)
  444. this.vinLoading = true
  445. vinCodeParse(formData).then(res => {
  446. if (res.type == 'application/json') {
  447. var reader = new FileReader()
  448. reader.addEventListener('loadend', function () {
  449. const obj = JSON.parse(reader.result)
  450. if (obj.status == 200) {
  451. _this.queryParam.vinCode = obj.data || ''
  452. // 移除表单项的校验结果
  453. _this.$refs.ruleForm.clearValidate('vinCode')
  454. } else {
  455. _this.$notification.error({
  456. message: '提示',
  457. description: obj.message
  458. })
  459. }
  460. _this.vinLoading = false
  461. document.getElementById('filed').value = ''
  462. })
  463. reader.readAsText(res)
  464. } else {
  465. _this.vinLoading = false
  466. }
  467. })
  468. },
  469. // 仓库
  470. getWarehouse () {
  471. warehouseAllList({}).then(res => {
  472. if (res.status == 200) {
  473. this.warehouseList = res.data
  474. } else {
  475. this.warehouseList = []
  476. }
  477. })
  478. },
  479. // 产品分类 change
  480. changeProductType (val, opt) {
  481. this.queryParam.productTypeSn1 = val[0] ? val[0] : ''
  482. this.queryParam.productTypeSn2 = val[1] ? val[1] : ''
  483. this.queryParam.productTypeSn3 = val[2] ? val[2] : ''
  484. }
  485. },
  486. watch: {
  487. cost (newValue, oldValue) {
  488. this.$emit('isCost', newValue)
  489. }
  490. }
  491. }
  492. </script>