chooseProduct.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. <template>
  2. <view class="chooseProduct-wrap">
  3. <!-- 产品列表 -->
  4. <view class="product-list-box">
  5. <scroll-view class="product-list-con" :style="{height: scrollH+'upx'}" scroll-y @scrolltolower="onreachBottom">
  6. <view class="product-list-item font_13" v-for="(item, index) in listData" :key="item.id">
  7. <view class="list-item-tit">
  8. <view class="item-tit ellipsis-one" :style="{borderColor: $config('primaryColor')}">{{item.productName}}</view>
  9. </view>
  10. <view class="list-item-con flex align_center justify_between">
  11. <view class="flex align_center justify_between flex_1">
  12. <view class="pimgs">
  13. <u-image :src="item.productMainImage?item.productMainImage:`../../static/${theme}/def_img@2x.png`" width="128" height="128" border-radius="10"></u-image>
  14. </view>
  15. <view class="flex_1">
  16. <view>产品编码:{{item.productCode || '--'}}</view>
  17. <view class="padding_3">原厂编码:{{item.productOrigCode || '--'}}</view>
  18. <view v-if="item.warehouseName || item.warehouseLocationName">仓库仓位:{{item.warehouseName}} > {{item.warehouseLocationName}}</view>
  19. </view>
  20. </view>
  21. <view class="list-item-btn">
  22. <u-icon class="item-btn-add" v-if="!item.saleQty" name="plus-circle" :color="$config('primaryColor')" size="40" @click="handleAdd(item, 'add')"></u-icon>
  23. <u-tag v-else text="已添加" type="info" mode="light" shape="circle" size="mini" style="vertical-align: text-top;" />
  24. </view>
  25. </view>
  26. <view class="list-item-footer flex align_center justify_between">
  27. <view class="footer-item" v-if="searchParams && searchParams.cost">
  28. <view>{{toThousands(item.putCost||0, 2)}}</view>
  29. <view class="color_6">成本价</view>
  30. </view>
  31. <view class="footer-item" v-if="searchParams && searchParams.cityPrice">
  32. <view>{{toThousands(item.dealerProduct && item.dealerProduct.cityPrice || 0, 2)}}</view>
  33. <view class="color_6">市级价</view>
  34. </view>
  35. <view class="footer-item">
  36. <view>{{toThousands(item.currentQty||0)}}{{item.unit}}</view>
  37. <view class="color_6">库存数量</view>
  38. </view>
  39. <view class="footer-item">
  40. <view>
  41. <text :style="{color: $config('errorColor')}">{{toThousands(item.price||0, 2)}}</text>
  42. <text v-if="item.origSalePriceFlag == 1">(原)</text>
  43. </view>
  44. <view class="color_6">参考售价</view>
  45. </view>
  46. </view>
  47. </view>
  48. <view v-if="listData && listData.length == 0">
  49. <u-empty :text="noDataText" mode="list" :img-width="200" :margin-top="30"></u-empty>
  50. </view>
  51. </scroll-view>
  52. </view>
  53. <!-- 合计 -->
  54. <view ref="productTotal" class="selected-box flex align_center justify_between">
  55. <view class="choose-info flex_1 flex align_center justify_between" @click="lookProduct">
  56. <text>已选 {{detailData && (detailData.totalCategory || detailData.totalCategory==0) ? toThousands(detailData.totalCategory) : '--'}} 款,合计 ¥{{detailData && (detailData.totalAmount || detailData.totalAmount==0) ? toThousands(detailData.totalAmount, 2) : '--'}}</text>
  57. <u-icon name="arrow-up" :color="$config('primaryColor')" size="34" class="close-circle"></u-icon>
  58. </view>
  59. <view class="choose-btn" @click="handleChoose" :style="{backgroundColor: $config('primaryColor')}">选好了</view>
  60. </view>
  61. <!-- 查询右侧弹框 -->
  62. <productSearch :openModal="openModal" :defaultParams="searchParams" @refresh="refresh" @close="openModal=false" />
  63. <!-- 添加/编辑产品 -->
  64. <productModal :openModal="openProductModal" :infoData="productInfo" @confirm="productConfirm" @close="openProductModal=false" />
  65. <!-- 已选产品 -->
  66. <selectedProductsModal ref="selectedProducts" :openModal="openSelectedModal" :nowData="detailData" @edit="handleEdit" @confirm="handleChoose" @refreshTotal="selectedProductTotal" @close="openSelectedModal=false" />
  67. <!-- 弹框 -->
  68. <common-modal :openModal="commonModal" :content="modalText" @confirm="handleCommon" @cancel="handleCancel" @close="commonModal=false" />
  69. </view>
  70. </template>
  71. <script>
  72. import ProductSearch from './productSearch.vue'
  73. import ProductModal from './productModal.vue'
  74. import SelectedProductsModal from './selectedProductsModal.vue'
  75. import commonModal from '@/pages/common/commonModal.vue'
  76. import { toThousands } from '@/libs/tools'
  77. import { querySumByProductLocation, stockByProductSn } from '@/api/stock'
  78. import { salesDetail, supperCodeByVin, salesDetailInsert, salesDetailUpdate } from '@/api/sales'
  79. export default{
  80. components: { ProductSearch, ProductModal, SelectedProductsModal, commonModal },
  81. data(){
  82. return{
  83. toThousands,
  84. listData: [],
  85. pageNo: 1,
  86. pageSize: 6,
  87. totalNum: 0,
  88. noDataText: '暂无数据',
  89. searchParams: null,
  90. openModal: false,
  91. theme: '',
  92. salesInfo: null, // 销售单信息
  93. scrollH: 0,
  94. openProductModal: false, // 编辑产品信息弹框是否显示
  95. productData: null, // 当前操作的产品信息
  96. productInfo: null, // 添加/编辑产品需要的参数
  97. chooseType: 'add', // 添加产品add,编辑产品edit
  98. commonModal: false, // 公共弹框是否显示
  99. modalText: '', // 公共弹框提示语
  100. commonType: 1, // 公共弹框类型 1为添加产品时库存不足,2为编辑产品时库存不足,3为售价低于定价,4为售价低于成本价
  101. openSelectedModal: false, // 已选产品弹框是否显示
  102. detailData: null, // 销售单详情数据
  103. editInfo: null, // 添加/编辑 提交的值
  104. }
  105. },
  106. onNavigationBarButtonTap(e){ // 标题栏 按钮操作
  107. this.openModal = true
  108. },
  109. onLoad(opt) {
  110. this.theme = getApp().globalData.theme
  111. if(opt){
  112. this.salesInfo = opt.data ? JSON.parse(opt.data) : null
  113. }
  114. this.init()
  115. const _this = this
  116. uni.getSystemInfo({
  117. success: function (res) {
  118. const winH = res.windowHeight * 2
  119. _this.scrollH = winH - 180
  120. }
  121. })
  122. },
  123. methods: {
  124. init(){
  125. this.getList(1) // 产品列表
  126. this.selectedProductTotal() // 已选产品合计
  127. },
  128. // 获取查询参数 刷新列表
  129. refresh(params){
  130. console.log('查询', params)
  131. const _this = this
  132. if(params.vinCode && params.vinCode.length == 17){
  133. // 查询vin码
  134. supperCodeByVin({ vin: params.vinCode }).then(res => {
  135. if(res.status == 200){
  136. params.productCodeList = res.data.partCodeList || []
  137. this.searchParams = params
  138. this.getList(1)
  139. }
  140. })
  141. }else{
  142. this.searchParams = params
  143. this.getList(1)
  144. }
  145. },
  146. // 列表
  147. getList(pageNo){
  148. const _this = this
  149. if (pageNo) {
  150. this.pageNo = pageNo
  151. }
  152. let params = {
  153. pageNo: this.pageNo,
  154. pageSize: this.pageSize
  155. }
  156. let searchParams = JSON.parse(JSON.stringify(this.searchParams))
  157. console.log(searchParams)
  158. if(searchParams){
  159. searchParams.brandName = undefined
  160. searchParams.nowData = undefined
  161. searchParams.warehouseName = undefined
  162. searchParams.cost = undefined
  163. searchParams.cityPrice = undefined
  164. }
  165. querySumByProductLocation(Object.assign(params, searchParams, { customerSn: this.salesInfo.buyerSn, salePriceType: this.salesInfo.priceType, salesBillSn: this.salesInfo.salesBillSn })).then(res => {
  166. if (res.status == 200) {
  167. if(res.data && res.data.list){
  168. res.data.list.map(item => {
  169. item.salesNums = 1
  170. item.currentQty = item.currentQty || 0
  171. item.price = item.lastSalePrice ? item.lastSalePrice : item.salePrice
  172. })
  173. }
  174. if(this.pageNo>1){
  175. this.listData = this.listData.concat(res.data.list || [])
  176. }else{
  177. this.listData = res.data.list || []
  178. }
  179. this.totalNum = res.data.count || 0
  180. } else {
  181. this.listData = []
  182. this.totalNum = 0
  183. this.noDataText = res.message
  184. }
  185. })
  186. },
  187. // scroll-view到底部加载更多
  188. onreachBottom() {
  189. if(this.listData.length < this.totalNum){
  190. this.pageNo += 1
  191. this.getList()
  192. }
  193. },
  194. // 添加/编辑产品
  195. handleAdd(data, type){
  196. console.log(data)
  197. if(type == 'add'){
  198. this.productInfo = {
  199. productName: data.productName,
  200. productMainImage: data.productMainImage,
  201. productCode: data.productCode,
  202. productOrigCode: data.productOrigCode,
  203. warehouseName: data.warehouseName,
  204. warehouseLocationName: data.warehouseLocationName,
  205. price: data.price,
  206. qty: 1
  207. }
  208. }else if(type == 'edit'){
  209. this.productInfo = {
  210. productName: data.productName,
  211. productMainImage: data.productMainImage,
  212. productCode: data.productCode,
  213. productOrigCode: data.productOrigCode,
  214. warehouseName: data.warehouseEntity && data.warehouseEntity.name,
  215. warehouseLocationName: data.warehouseLocationEntity && data.warehouseLocationEntity.name,
  216. price: data.price,
  217. qty: data.qty
  218. }
  219. }
  220. this.openProductModal = true
  221. this.chooseType = type
  222. this.productData = data
  223. },
  224. // 已选产品 编辑
  225. handleEdit(data){
  226. console.log(data)
  227. this.handleAdd(data, 'edit')
  228. },
  229. // 选好了
  230. handleChoose(){
  231. uni.redirectTo({ url: '/pages/sales/edit?pageType=edit&data='+JSON.stringify(this.detailData) })
  232. },
  233. // 查看已选产品
  234. lookProduct(){
  235. this.openSelectedModal = true
  236. },
  237. // 确认产品信息
  238. productConfirm(data){
  239. this.editInfo = data
  240. if(this.chooseType == 'add'){
  241. this.validatePrice() //验证 售价是否低于定价
  242. }else if(this.chooseType == 'edit'){
  243. this.validateStock() //验证 库存是否不足
  244. }
  245. },
  246. // 售价低于定价
  247. validatePrice(){
  248. if (this.productData.lastSalePrice && (this.editInfo.price < this.productData.salePrice)) { // 售价低于定价
  249. this.commonType = 1
  250. this.modalText = '售价低于定价,确认要添加吗?'
  251. this.commonModal = true
  252. }else{
  253. this.validateStock() //验证 库存是否不足
  254. }
  255. },
  256. // 库存不足
  257. validateStock(){
  258. if(this.chooseType == 'add'){ // 添加产品
  259. if (this.productData.currentQty < this.editInfo.qty) {
  260. this.commonType = 2
  261. this.modalText = '库存不足,将产生急件,确认要添加吗?'
  262. this.commonModal = true
  263. }else{
  264. this.validateCost() //验证 售价是否低于成本价
  265. }
  266. }else if(this.chooseType == 'edit'){ // 编辑产品
  267. // 校验库存
  268. stockByProductSn({ productSn: this.productData.productSn }).then(res => {
  269. if (res.status == 200) {
  270. console.log(!res.data.currentStockQty, this.editInfo.qty <= res.data.currentStockQty)
  271. console.log(!res.data.currentStockQty || this.editInfo.qty <= res.data.currentStockQty)
  272. if (res.data && (!res.data.currentStockQty || this.editInfo.qty <= res.data.currentStockQty)) {
  273. this.editProduct()
  274. } else { // 库存不足
  275. this.commonType = 3
  276. this.modalText = '库存不足,将产生急件,确认修改吗?'
  277. this.commonModal = true
  278. }
  279. }
  280. })
  281. }
  282. },
  283. // 售价低于成本价
  284. validateCost(){
  285. if (this.productData.putCost > this.editInfo.price) {
  286. this.commonType = 4
  287. this.modalText = '售价低于成本价,确认要添加吗?'
  288. this.commonModal = true
  289. }else{
  290. this.addProduct()
  291. }
  292. },
  293. // 添加产品
  294. addProduct(){
  295. let params = {
  296. buyerSn: this.detailData.buyerSn,
  297. productSn: this.productData.productSn,
  298. cost: this.productData.putCost,
  299. price: this.editInfo.price,
  300. qty: this.editInfo.qty,
  301. salesBillSn: this.detailData.salesBillSn,
  302. salesBillNo: this.detailData.salesBillNo,
  303. warehouseSn: this.productData.warehouseSn,
  304. warehouseLocationSn: this.productData.warehouseLocationSn,
  305. stockSn: this.productData.stockSn
  306. }
  307. salesDetailInsert(params).then(res => {
  308. if(res.status == 200){
  309. this.changeList(params) // 变更 列表产品可选状态
  310. this.selectedProductTotal() // 已选产品合计
  311. this.commonModal = false
  312. this.openProductModal = false
  313. }
  314. })
  315. },
  316. // 编辑产品
  317. editProduct(){
  318. let params = {
  319. id: this.productData.id,
  320. qty: this.editInfo.qty,
  321. price: this.editInfo.price,
  322. productSn: this.productData.productSn,
  323. salesBillSn: this.detailData.salesBillSn,
  324. }
  325. salesDetailUpdate(params).then(res => {
  326. if(res.status == 200){
  327. this.$refs.selectedProducts.getList(1)
  328. this.selectedProductTotal() // 已选产品合计
  329. this.commonModal = false
  330. this.openProductModal = false
  331. }
  332. })
  333. },
  334. // 更改产品列表参数
  335. changeList(params){
  336. this.listData.map(item => {
  337. if((item.stockSn == params.stockSn) && (item.warehouseLocationSn == params.warehouseLocationSn)){
  338. item.saleQty = 1 // 非0即可,用于判断是否显示添加产品按钮
  339. }
  340. })
  341. },
  342. // 公共弹框 确定
  343. handleCommon(){
  344. if(this.commonType == 1){ // 添加产品时售价低于定价
  345. this.validateStock() //验证 库存是否不足
  346. }else if(this.commonType == 2){ // 添加产品时库存不足
  347. this.validateCost() //验证 售价是否低于成本价
  348. }else if(this.commonType == 3){ // 编辑产品时库存不足
  349. this.editProduct()
  350. }else if(this.commonType == 4){ // 添加产品时售价低于成本价
  351. this.addProduct()
  352. }
  353. },
  354. // 公共弹框 取消
  355. handleCancel(){
  356. this.openProductModal = false
  357. },
  358. // 已选产品 提交
  359. selectedConfirm(){},
  360. // 已选产品合计
  361. selectedProductTotal(){
  362. salesDetail({ id: this.salesInfo.id }).then(res => {
  363. if(res.status == 200){
  364. this.detailData = res.data
  365. }else{
  366. this.detailData = null
  367. }
  368. })
  369. },
  370. }
  371. }
  372. </script>
  373. <style lang="scss">
  374. .chooseProduct-wrap{
  375. width: 100%;
  376. position: relative;
  377. .padding_3{
  378. padding: 6upx 0;
  379. }
  380. .color_6{
  381. color: #666;
  382. }
  383. .product-list-box{
  384. padding: 20upx 20upx;
  385. .product-list-con{
  386. .product-list-item{
  387. background: #ffffff;
  388. padding: 20upx 20upx 0;
  389. margin-bottom: 25upx;
  390. border-radius: 25upx;
  391. box-shadow: 1px 1px 3px #EEEEEE;
  392. .list-item-tit{
  393. padding-bottom: 12upx;
  394. border-bottom: 1px solid #e4e7ed;
  395. .item-tit{
  396. font-weight: bold;
  397. color: rgb(48, 49, 51);
  398. font-size: 28upx;
  399. padding-left: 10upx;
  400. border-left: 6upx solid #000;
  401. line-height: 1;
  402. }
  403. }
  404. .list-item-con{
  405. padding: 14upx 0 16upx;
  406. font-size: 26upx;
  407. .pimgs{
  408. margin-right: 16upx;
  409. }
  410. .list-item-btn{
  411. .item-btn-add{
  412. padding: 30upx 30upx;
  413. }
  414. }
  415. }
  416. .list-item-footer{
  417. border-top: 1px solid #e4e7ed;
  418. .footer-item{
  419. width: 50%;
  420. text-align: center;
  421. border-right: 1px solid #e4e7ed;
  422. font-size: 26upx;
  423. padding: 8upx 0 12upx;
  424. }
  425. .footer-item:last-child{
  426. border: none;
  427. }
  428. }
  429. }
  430. }
  431. }
  432. .selected-box{
  433. background-color: #fff;
  434. box-shadow: 1px -1px 3px #EEEEEE;
  435. .choose-info{
  436. padding: 0 30upx;
  437. }
  438. .choose-btn{
  439. color: #fff;
  440. width: 28%;
  441. padding: 26upx 0;
  442. text-align: center;
  443. }
  444. }
  445. }
  446. </style>