自主产品,供应链食堂系统。将两个端拆开了。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

505 lines
14 KiB

5 years ago
  1. <template>
  2. <view>
  3. <view class="box">
  4. <view class="title">报价清单</view>
  5. <view class="lf-font-24 lf-color-gray lf-m-t-5">请在以下物资信息表内填写报价</view>
  6. </view>
  7. <!-- 修饰条 -->
  8. <self-line></self-line>
  9. <view class="box lf-row-between relation">
  10. <view>
  11. <text class="title">关联食堂</text>
  12. <text class="lf-font-24 lf-color-555 lf-m-l-10">(多选)</text>
  13. </view>
  14. <view class="lf-font-24 lf-color-gray lf-text-right lf-row-center" style="width: 370rpx; justify-content: flex-end;" @click="switchRelation">
  15. <view class="lf-line-1">{{ selectName }}</view>
  16. <u-icon name="arrow-right" class="lf-text-vertical"></u-icon>
  17. </view>
  18. <view class="mask" :style="{top: node_top +'px'}" v-if="is_show" @click="is_show = false">
  19. <view class="list">
  20. <view class="lf-row-between item" v-for="(item, index) in relation_list" :key="index" @click.stop="selectItem(index)">
  21. <view>{{ item.canteen_name }}</view>
  22. <u-icon name="checkmark-circle" color="#1833F2" size="40" v-if="item.checked"></u-icon>
  23. </view>
  24. </view>
  25. </view>
  26. </view>
  27. <self-line></self-line>
  28. <!-- 报价时间 -->
  29. <view class="lf-row-between lf-p-30 lf-p-l-32 lf-p-r-32 lf-font-28">
  30. <view class="lf-color-black">报价生效时间</view>
  31. <picker mode="date" :value="deadline_start" @change="pickerChange($event, 'deadline_start')">
  32. <view class="lf-color-555 lf-text-right" style="width: 400rpx;">{{ deadline_start || '请选择...' }}</view>
  33. </picker>
  34. </view>
  35. <view class="lf-row-between lf-p-30 lf-p-l-32 lf-p-r-32 lf-font-28">
  36. <view class="lf-color-black">报价失效时间</view>
  37. <picker mode="date" :value="deadline_end" @change="pickerChange($event, 'deadline_end')">
  38. <view class="lf-color-555 lf-text-right" style="width: 400rpx;">{{ deadline_end || '请选择...' }}</view>
  39. </picker>
  40. </view>
  41. <self-line></self-line>
  42. <!-- 物料table -->
  43. <view class="box">
  44. <view class="lf-font-32 lf-color-black lf-font-bold lf-m-b-20">报价明细</view>
  45. <wyb-table :first-line-fixed="true"
  46. contentBgColor="#eef6fe"
  47. :headers="headers"
  48. :contents="contents"
  49. @onInputChange="onInputChange"
  50. @onButtonClick="onButtonClick"
  51. width="100%" height="80vh"></wyb-table>
  52. </view>
  53. <view style="height: 140rpx;"></view>
  54. <!-- 操作按钮 -->
  55. <view class="fixed-bottom">
  56. <button class="btn btn1" @click="save(0)">临时保存</button>
  57. <button class="btn btn2" @click="save(1)">直接报价</button>
  58. </view>
  59. </view>
  60. </template>
  61. <script>
  62. import wybTable from '@/components/wyb-table/wyb-table';
  63. let app = getApp();
  64. export default {
  65. components: {
  66. wybTable
  67. },
  68. data(){
  69. return {
  70. headers: [{
  71. label: '物资名称',
  72. key: 'name'
  73. },{
  74. label: '规格',
  75. key: 'spec'
  76. },{
  77. label: '单位',
  78. key: 'unit'
  79. },{
  80. label: '分类',
  81. key: 'category'
  82. },{
  83. label: '品牌',
  84. key: 'brand'
  85. },{
  86. label: '品级',
  87. key: 'quality_level'
  88. },{
  89. label: '编号',
  90. key: 'number'
  91. },{
  92. label: '起购数',
  93. key: 'purchase_limit'
  94. },{
  95. label: '含税价',
  96. key: 'tax_price'
  97. },{
  98. label: '不含税价',
  99. key: 'non_tax_price'
  100. },{
  101. label: '操作',
  102. key: 'operation'
  103. }],
  104. contents: [],
  105. is_show: false,
  106. relation_list: [], // 关联食堂列表
  107. node_top: 0,
  108. code: '', // 订单号,批次号,如果有
  109. type: 0,
  110. deadline_start: '',
  111. deadline_end: ''
  112. }
  113. },
  114. computed: {
  115. selectName(){
  116. let arr = [];
  117. this.relation_list.map(item => {
  118. if(item.checked){
  119. arr.push(item.canteen_name);
  120. }
  121. });
  122. let str = '请选择...';
  123. if(arr.length > 0){
  124. str = arr.join(',');
  125. }
  126. return str;
  127. }
  128. },
  129. onLoad(options){
  130. this.code = options.code || '';
  131. this.type = options.type || 0;
  132. if(options.type == 1){
  133. // 编辑,不可更换食堂
  134. this.materialListByOrder();
  135. }else if(options.type == 2){
  136. // 复用订单号
  137. this.materialListByOrder();
  138. }else if(options.type == 3){
  139. // 复用批次号
  140. this.materialListByBatch();
  141. }else{
  142. // 单纯发起报价
  143. this.getMaterialList();
  144. }
  145. },
  146. onReady(){
  147. let that = this;
  148. let info = uni.createSelectorQuery().select(".relation");
  149.     info.boundingClientRect(function(data) {
  150. let num = app.globalData.customBarH;
  151. num += data.height;
  152. num += data.top;
  153. that.node_top = num;
  154.    }).exec()
  155. },
  156. onPageScroll(){
  157. if(this.is_show){
  158. this.is_show = false;
  159. }
  160. },
  161. methods: {
  162. // 日期选择器值被改变
  163. pickerChange(event, current_name){
  164. console.log(current_name)
  165. if(current_name == 'deadline_start') {
  166. // PS 获取30天后日期
  167. var date1 = new Date(event.detail.value);
  168. var date2 = new Date(date1);
  169. date2.setDate(date1.getDate() + 30);
  170. console.log(this.$shared.recordTime(date2, '-', 'date'))
  171. this[current_name] = event.detail.value;
  172. this.deadline_end = this.$shared.recordTime(date2, '-', 'date')
  173. }else {
  174. this[current_name] = event.detail.value;
  175. }
  176. },
  177. // 获取物资列表
  178. getMaterialList(){
  179. this.$http(this.API.API_SUPPLIER_MATERIALLIST).then(res => {
  180. let list = res.data.spec || [];
  181. let contents = list.map(item => {
  182. return {
  183. name: item?.material?.m_name || '',
  184. material_id: item?.material?.id || 0,
  185. spec: item.name,
  186. spec_id: item.id,
  187. brand: item?.material?.brand || '',
  188. quality_level: item?.material?.quality_level || '',
  189. number: item?.material?.m_sn || '',
  190. purchase_limit: {edit: true, value: 1},
  191. tax_price: {edit: true, value: ''},
  192. non_tax_price: {edit: true, value: ''},
  193. operation: {button: true, key: 'delete', value: '删除'},
  194. unit: item?.material?.unit?.unit_name || '',
  195. category: item?.material?.category?.m_cate_name || ''
  196. }
  197. })
  198. this.contents = contents;
  199. this.getCanteenList();
  200. })
  201. },
  202. // 复用报价订单号 & 编辑共用
  203. materialListByOrder(){
  204. this.$http(this.API.API_SUPPLIER_QUOTATIONREUSEBYORDER, {
  205. q_sn: this.code
  206. }).then(res => {
  207. let list = res.data.order || [];
  208. let canteen = res.data.canteen || [];
  209. // 处理表格显示
  210. let contents = list.map(item => {
  211. let obj = {
  212. name: item?.material?.m_name || '',
  213. material_id: item?.material?.id || 0,
  214. spec: item.name,
  215. spec_id: item.id,
  216. brand: item?.material?.brand || '',
  217. quality_level: item?.material?.quality_level || '',
  218. number: item?.material?.m_sn || '',
  219. purchase_limit: {edit: true, value: item?.quotation_item?.purchase_limit || ''},
  220. tax_price: {edit: true, value: item?.quotation_item?.tax_price || ''},
  221. non_tax_price: {edit: true, value: item?.quotation_item?.non_tax_price || ''},
  222. quotation_id: item?.quotation_item?.id || 0,
  223. operation: {button: true, key: 'delete', value: '删除'},
  224. unit: item?.material?.unit?.unit_name || '',
  225. category: item?.material?.category?.m_cate_name || ''
  226. }
  227. if(item?.material?.state && item?.material?.state != '启用'){
  228. obj.disabled = true;
  229. }
  230. return obj;
  231. })
  232. this.contents = contents;
  233. // 处理报价生效、失效时间
  234. let deadline_start = '';
  235. let deadline_end = '';
  236. if(list[0] && list[0]?.quotation_item?.quotation){
  237. let quotation = list[0]?.quotation_item?.quotation || {};
  238. if(quotation.deadline_start){
  239. deadline_start = quotation.deadline_start.split(' ')[0];
  240. }
  241. if(quotation.deadline){
  242. deadline_end = quotation.deadline.split(' ')[0];
  243. }
  244. }
  245. this.deadline_start = deadline_start;
  246. this.deadline_end = deadline_end;
  247. this.getCanteenList(canteen);
  248. })
  249. },
  250. // 复用批次号
  251. materialListByBatch(){
  252. this.$http(this.API.API_SUPPLIER_QUOTATIONREUSEBYBATCH, {
  253. batch_sn: this.code
  254. }).then(res => {
  255. console.log("materialListByBatch", res);
  256. let list = res.data.order || [];
  257. let canteen = res.data.canteen || [];
  258. // 处理表格显示
  259. let contents = list.map(item => {
  260. return {
  261. name: item?.material?.m_name || '',
  262. material_id: item?.material?.id || 0,
  263. spec: item.name,
  264. spec_id: item.id,
  265. brand: item?.material?.brand || '',
  266. quality_level: item?.material?.quality_level || '',
  267. number: item?.material?.m_sn || '',
  268. purchase_limit: {edit: true, value: item?.quotation?.purchase_limit || ''},
  269. tax_price: {edit: true, value: item?.quotation?.tax_price || ''},
  270. non_tax_price: {edit: true, value: item?.quotation?.non_tax_price || ''}
  271. }
  272. })
  273. this.contents = contents;
  274. // 处理报价生效、失效时间
  275. let deadline_start = '';
  276. let deadline_end = '';
  277. if(list[0] && list[0]?.quotation_item?.quotation){
  278. let quotation = list[0]?.quotation_item?.quotation || {};
  279. if(quotation.deadline_start){
  280. deadline_start = quotation.deadline_start.split(' ')[0];
  281. }
  282. if(quotation.deadline){
  283. deadline_end = quotation.deadline.split(' ')[0];
  284. }
  285. }
  286. this.deadline_start = deadline_start;
  287. this.deadline_end = deadline_end;
  288. this.getCanteenList(canteen);
  289. })
  290. },
  291. // 关联食堂列表
  292. getCanteenList(canteen = []){
  293. this.$http(this.API.API_SUPPLIER_CANTEENLIST).then(res => {
  294. let list = res.data.list.map(item => {
  295. item.checked = false;
  296. canteen.map(ct => {
  297. if(ct == item.id){
  298. item.checked = true;
  299. }
  300. })
  301. return item;
  302. })
  303. this.relation_list = list;
  304. })
  305. },
  306. // 监听表格被输入
  307. onInputChange(event){
  308. this.contents[event.contentIndex][event.key].value = event.detailValue;
  309. },
  310. // table操作按钮被点击
  311. onButtonClick(event){
  312. if(event.content.key == 'delete'){
  313. let contentIndex = event.contentIndex;
  314. let name = event.lineData.name;
  315. let spec = event.lineData.spec;
  316. uni.showModal({
  317. title: '温馨提示',
  318. content: `确定删除 ${name}-${spec} 吗?`,
  319. confirmColor: '#1833F2',
  320. success: result => {
  321. if(result.confirm){
  322. this.contents.splice(contentIndex, 1);
  323. }
  324. }
  325. })
  326. }
  327. },
  328. // 切换显示关联食堂modal
  329. switchRelation(){
  330. if(this.type == 1) return this.$msg('编辑不可更换关联食堂哦');
  331. this.is_show = !this.is_show;
  332. },
  333. // 选择食堂
  334. selectItem(index){
  335. this.relation_list[index].checked = !this.relation_list[index].checked;
  336. },
  337. // 报价订单编辑时保存
  338. editMaterial(_t){
  339. // 物资列表
  340. let list = [];
  341. this.contents.map(item => {
  342. list.push({
  343. id: item.quotation_id,
  344. tax_price: item.tax_price.value,
  345. non_tax_price: item.non_tax_price.value,
  346. purchase_limit: Number(item.purchase_limit.value) || 1
  347. })
  348. });
  349. // 操作状态,是保存还是直接发起
  350. let state = ['待发起', '待审核'][_t];
  351. this.$http(this.API.API_SUPPLIER_QUOTATIONSAVE, {
  352. data: list,
  353. state: state,
  354. q_sn: this.code,
  355. start: this.deadline_start,
  356. end: this.deadline_end
  357. }).then(res => {
  358. this.$msg('操作成功').then(result => {
  359. this.$toBack();
  360. })
  361. })
  362. },
  363. // 保存
  364. save(_t){
  365. // 拦截是编辑的情况
  366. if(this.type == 1){
  367. this.editMaterial(_t);
  368. return;
  369. }
  370. // 物资列表
  371. let list = [];
  372. this.contents.map(item => {
  373. if(item.tax_price.value && item.non_tax_price.value){
  374. list.push({
  375. m_id: item.material_id,
  376. m_spec_id: item.spec_id,
  377. tax_price: item.tax_price.value,
  378. non_tax_price: item.non_tax_price.value,
  379. purchase_limit: Number(item.purchase_limit.value) || 1
  380. })
  381. }
  382. });
  383. // 关联食堂
  384. let canteen_ids = [];
  385. this.relation_list.map(item => {
  386. if(item.checked){
  387. canteen_ids.push(item.id);
  388. }
  389. })
  390. if(canteen_ids.length <= 0){
  391. return this.$msg('您未选择关联食堂哦')
  392. }
  393. if(!this.deadline_start){
  394. return this.$msg('您未选择报价生效时间哦')
  395. }
  396. if(!this.deadline_end){
  397. return this.$msg('您未选择报价失效时间哦')
  398. }
  399. if(list.length <= 0){
  400. return this.$msg('请补充完整物资报价信息')
  401. }
  402. // 操作状态,是保存还是直接发起
  403. let state = ['待发起', '待审核'][_t];
  404. this.$http(this.API.API_SUPPLIER_QUOTATIONAPPLY, {
  405. data: list,
  406. state: state,
  407. canteen_ids: canteen_ids,
  408. start: this.deadline_start,
  409. end: this.deadline_end
  410. }).then(res => {
  411. this.$msg(res.data).then(result => {
  412. this.$toBack();
  413. })
  414. })
  415. }
  416. }
  417. }
  418. </script>
  419. <style>
  420. page{
  421. overflow: hidden;
  422. }
  423. </style>
  424. <style lang="scss" scoped="scoped">
  425. .lf-m-t-5{
  426. margin-top: 5rpx;
  427. }
  428. .box{
  429. padding: 30rpx 32rpx;
  430. width: 100%;
  431. height: max-content;
  432. box-sizing: border-box;
  433. }
  434. .title{
  435. color: #222222;
  436. font-size: 28rpx;
  437. font-weight: bold;
  438. }
  439. .fixed-bottom{
  440. position: fixed;
  441. bottom: 0rpx;
  442. left: 0rpx;
  443. z-index: 99;
  444. width: 750rpx;
  445. height: 98rpx;
  446. display: flex;
  447. justify-content: center;
  448. align-items: center;
  449. border-top: 1rpx solid #E5E5E5;
  450. background-color: #fff;
  451. .btn{
  452. width: 320rpx;
  453. height: 82rpx;
  454. border-radius: 41rpx;
  455. margin: 0;
  456. padding: 0;
  457. font-size: 32rpx;
  458. display: flex;
  459. justify-content: center;
  460. align-items: center;
  461. }
  462. .btn1{
  463. border: 2rpx solid #555555;
  464. opacity: .5;
  465. }
  466. .btn2{
  467. background: #1833F2;
  468. color: #FFFFFF;
  469. margin-left: 50rpx;
  470. }
  471. }
  472. .relation{
  473. position: relative;
  474. border-bottom: 1rpx solid #E5E5E5;
  475. }
  476. .mask{
  477. position: fixed;
  478. background-color: rgba(0,0,0,0.4);
  479. width: 100%;
  480. // top: 149px;
  481. bottom: 0;
  482. left: 0;
  483. z-index: 100;
  484. .list{
  485. min-height: max-content;
  486. max-height: 500rpx;
  487. overflow: scroll;
  488. background-color: #FFFFFF;
  489. width: 100%;
  490. .item{
  491. height: 92rpx;
  492. padding: 0 32rpx;
  493. border-bottom: 1rpx solid #E5E5E5;
  494. color: #222222;
  495. font-size: 28rpx;
  496. }
  497. }
  498. }
  499. </style>