Explorar el Código

手持-还库任务

zhaohuanhuan hace 2 meses
padre
commit
67dcb36611

+ 5 - 0
src/hooks/basic/menu.js

@@ -79,6 +79,11 @@ export default function() {
               icon: 'newspaper-o',
               path: 'inventory-transfer',
             },
+            {
+              title: '还库任务',
+              icon: 'newspaper-o',
+              path: 'return-list',
+            },
           ],
         },
         {

+ 12 - 0
src/router/index.ts

@@ -176,6 +176,18 @@ const routes: RouteRecordRaw[] = [
     meta:{title:'面单识别'},
     component: () => import('@/views/inbound/photoOCR/index.vue')
   },
+  {
+    path: '/return-list',
+    name: 'ReturnList',
+    meta:{title:'还库列表'},
+    component: () => import('@/views/inventory/returnTask/list/index.vue')
+  },
+  {
+    path: '/return-task',
+    name: 'ReturnTask',
+    meta:{title:'还库任务'},
+    component: () => import('@/views/inventory/returnTask/task/index.vue')
+  },
 ];
 
 // 创建路由实例

+ 217 - 0
src/views/inventory/returnTask/list/index.vue

@@ -0,0 +1,217 @@
+<template>
+  <div class="container">
+    <div class="task">
+      <div class="top">
+        <div class="nav-bar">
+          <van-nav-bar title="还库任务" left-arrow  @click-left="goBack" @click-right="onClickRight" >
+            <template #left>
+              <van-icon name="arrow-left" size="25"   />
+              <div style="color: #fff;height: 46px;padding-right:20px;line-height: 46px" >返回</div>
+            </template>
+            <template #right>
+              <div style="color: #fff;line-height: 46px " >创建任务</div>
+            </template>
+          </van-nav-bar>
+        </div>
+        <div class="content">
+          <van-pull-refresh v-model="loading" @refresh="onRefresh" :style="{ 'max-height': computedMaxHeight,'min-height':computedMaxHeight ,'overflow':'auto'}" >
+            <van-list
+              v-model="loadingMore"
+              :finished="!hasMore"
+              finished-text="没有更多了"
+              @load="loadMore"
+              :style="{ 'max-height': computedMaxHeight,'min-height':computedMaxHeight ,'overflow':'auto'}"
+            >
+              <table border="1" style="width: 100%;border-collapse: collapse;text-align: center;table-layout: fixed;" >
+                <thead>
+                <tr>
+                  <th>任务号</th>
+                  <th style="width: 50px">状态</th>
+                  <th style="width: 70px">创建日期</th>
+                  <th style="width: 60px">剩余数量</th>
+                  <th style="width: 70px">操作</th>
+                </tr>
+                </thead>
+                <tbody>
+                <tr v-for="(row, rowIndex) in taskList" :key="rowIndex">
+                  <td style="word-wrap: break-word" >{{ row.code }}</td>
+                  <td style="word-wrap: break-word" >{{ statusMap[row.status] || row.status }}</td>
+                  <td style="word-wrap: break-word;font-size:11px">26012107:09</td>
+                  <td style="word-wrap: break-word;">{{ row.locationQuantity }}</td>
+                  <td>
+                    <van-button type="primary" size="mini" plain  @click="linkTask(row.code,'MoveDown')">作业</van-button>
+                    <van-button type="primary" size="mini" plain @click="linkTask(row.code,'MoveDown')">查看</van-button>
+                  </td>
+                </tr>
+                <tr v-if="taskList.length==0 && !loadingMore">
+                  <td colspan="5">
+                    <van-empty :image="nodataUrl" image-size="140" >
+                      <van-button round type="primary" class="bottom-button" size="small" @click="loadData">刷新</van-button>
+                    </van-empty>
+                  </td>
+                </tr>
+                </tbody>
+              </table>
+            </van-list>
+            <van-back-top right="80vw" bottom="10vh" />
+          </van-pull-refresh>
+        </div>
+      </div>
+    </div>
+    <input-barcode ref="inputBarcodeRef"  @setBarcode="setBarcode"  />
+  </div>
+</template>
+
+<script setup>
+import { computed, onMounted, ref } from 'vue'
+import { getHeader, goBack, scanError } from '@/utils/android'
+import { useStore } from '@/store/modules/user'
+import { getMoveTaskList } from '@/api/transferMove/index'
+import { showToast } from 'vant'
+import nodataUrl from '@/assets/nodata.png'
+import { closeLoading, showLoading } from '@/utils/loading'
+import { useRouter } from 'vue-router'
+import { toMap } from '@/utils/dataType.js'
+import InputBarcode from '@/views/outbound/picking/components/InputBarcode.vue'
+import { openListener, scanInit } from '@/utils/keydownListener.js'
+const router = useRouter()
+try {
+  getHeader()
+}catch (error) {
+  router.push('/login')
+}
+const topHeight=ref(46)
+const computedMaxHeight = computed(() => {
+  return `calc(100vh - ${topHeight.value}px)`;
+});
+const storeUser = useStore()
+const warehouse = storeUser.warehouse
+//任务列表
+const taskList=ref([])
+const statusMap=ref({
+  'CREATED':'创建',
+  'IN_PROGRESS':'进行中',
+  'FINISHED':'完成'
+})
+
+// 分页相关状态
+const pageNum = ref(1)
+const pageSize = ref(20)
+const hasMore = ref(true)
+const loadingMore = ref(false)
+
+const loadData = async (isLoadMore = false) => {
+  if (!isLoadMore) {
+    showLoading()
+    pageNum.value = 1
+    taskList.value = []
+  } else {
+    loadingMore.value = true
+  }
+
+  try {
+    const params = {
+      warehouseCode: warehouse,
+      pageNum: pageNum.value,
+      pageSize: pageSize.value
+    }
+    const res = await getMoveTaskList(params)
+
+    if (isLoadMore) {
+      taskList.value = [...taskList.value, ...res.data]
+    } else {
+      taskList.value = res.data
+    }
+
+    // 判断是否还有更多数据
+    hasMore.value = res.data && res.data.length === pageSize.value
+  } finally {
+    if (!isLoadMore) {
+      closeLoading()
+    } else {
+      loadingMore.value = false
+    }
+  }
+}
+
+// 上拉加载更多
+const loadMore = () => {
+  if (hasMore.value && !loadingMore.value) {
+    pageNum.value++
+    loadData(true)
+  }
+}
+loadData()
+
+const inputBarcodeRef=ref(null)
+const onClickRight=()=>{
+  inputBarcodeRef.value?.show(undefined,'请扫描反拣容器','')
+}
+const setBarcode=(code)=>{
+  const checkContainer = `FJ-${warehouse}-`
+  if (!code.includes(checkContainer)) {
+    scanError()
+    setTimeout(()=>{
+      inputBarcodeRef.value?.show('', '请扫描反拣容器', '扫描容器不是反拣容器,请重新扫描')
+    },300)
+    return
+  }
+  router.push({ name:'ReturnTask', query: { code: code,status:0 } });
+}
+
+// 进入任务
+const linkTask = (code, name) => {
+  if (code !== 0) {
+    localStorage.setItem('MOVETASKCODE', code);
+  }
+  let taskCode = localStorage.getItem('MOVETASKCODE') || code;
+  const listMap = toMap(taskList.value, 'code');
+  if (taskCode == 0) {
+    taskCode = taskList.value.length > 0
+      ? taskList.value[0].code
+      : listMap[taskCode]?.code || code
+  } else {
+    taskCode = taskList.value.length > 0?listMap[taskCode]?.code || taskList.value[0].code:0
+  }
+  router.push({ name, query: { code: taskCode } });
+  if (taskCode !== 0) {
+    localStorage.setItem('MOVETASKCODE', taskCode);
+  }
+};
+
+/**
+ * 下拉刷新
+ */
+const loading = ref(false)
+const onRefresh = () => {
+  setTimeout(() => {
+    loadData(false)
+    showToast('刷新成功')
+    loading.value = false
+  }, 1000)
+}
+
+window.onRefresh = loadData
+</script>
+
+<style scoped lang="sass">
+.container
+  width: 100%
+
+  .task
+    display: flex
+    flex-direction: column
+    height: 100vh
+
+    .top
+      flex: 1
+      display: flex
+      flex-direction: column
+
+      .nav-bar
+        height: 46px
+
+      .content
+        flex: 1
+        font-size: 13px
+</style>

+ 601 - 0
src/views/inventory/returnTask/task/index.vue

@@ -0,0 +1,601 @@
+<template>
+  <div class="container">
+    <van-nav-bar
+      title="还库任务"
+      left-arrow
+      fixed
+      placeholder
+      @click-left="goBack"
+    >
+      <template #left>
+        <van-icon name="arrow-left" size="25" />
+        <div  style="color: #fff">返回</div>
+      </template>
+      <template #right>
+        <div style="color: #fff;line-height: 46px " @click="">完成</div>
+        <div style="padding:14px 0 12px 6px" @click="onClickRightIcon" >
+          <van-icon name="list-switch" size="25"   />
+        </div>
+      </template>
+    </van-nav-bar>
+    <div class="move-stock">
+      <div class="code">
+        <div class="code-title">
+          <div>{{ containerNo || '' }}</div>
+          <div class="code-tips">
+            <van-notice-bar :background="'none'" :speed="50" :text="tips" />
+          </div>
+<!--          <van-button plain size="mini" type="primary" @click="_setContainerNo()">切换反拣容器</van-button>-->
+        </div>
+        <div class="code-input">
+          <van-search
+            ref="searchRef"
+            v-model="searchBarcode"
+            placeholder="请扫描商品条码"
+            @search="_handlerScan(searchBarcode)"
+            label="商品条码:"
+            left-icon=""
+            :class="[scanType===2?'search-input-barcode':'','van-hairline--bottom']"
+            @focus="scanType=2"
+            autocomplete="off"
+          >
+          </van-search>
+<!--          <van-search-->
+<!--            v-model="location"-->
+<!--            placeholder="请扫描还库库位"-->
+<!--            label="还库库位:"-->
+<!--            left-icon=""-->
+<!--            @search="_handlerScan(location)"-->
+<!--            :class="scanType===3?'search-input-barcode':''"-->
+<!--            @focus="scanType=3"-->
+<!--            autocomplete="off"-->
+<!--          >-->
+<!--          </van-search>-->
+        </div>
+      </div>
+      <div class="move-stock-content">
+        <table class="compact-table">
+          <colgroup>
+            <col v-for="i in 10" style="width: 10%;">
+          </colgroup>
+          <tbody>
+          <tr>
+            <td colspan="3">格口</td>
+            <td colspan="7">3</td>
+          </tr>
+          </tbody>
+        </table>
+      </div>
+      <div class="move-stock-list">
+        <table class="task-table">
+          <thead>
+          <tr>
+            <th>商品条码</th>
+            <th>商品名称</th>
+            <th>格口号</th>
+            <th>数量</th>
+          </tr>
+          </thead>
+          <tbody>
+          <tr v-for="(item, index) in moveList" :key="index"  v-if="moveList.length>0">
+            <td>{{ item.sku }}</td>
+            <td>{{ item.productionDate }}</td>
+            <td>{{ item.expirationDate }}</td>
+            <td>{{ item.attributeWarehouse }}</td>
+          </tr>
+          <tr v-else>
+            <td colspan="4">
+              <van-empty :image="nodataUrl" image-size="120"  />
+            </td>
+          </tr>
+          </tbody>
+        </table>
+      </div>
+    </div>
+    <!-- 弹出框 -->
+    <van-action-sheet
+      v-model:show="modeTrueFalseBy"
+      :actions="actions"
+      cancel-text="取消"
+      close-on-click-action
+      @select="onSelectMode"
+    />
+    <!-- 条码输入组件 -->
+    <input-barcode :back="back" @setBarcode="setBarcode" ref="inputBarcodeRef" />
+    <van-dialog v-model:show="moveStockTrueFalseBy"
+                :beforeClose="beforeClose"
+                :title="'商品条码:'+ model.sku +',还库:'+location" show-cancel-button  >
+      <van-form>
+        <van-field
+          v-model="moveCount"
+          center
+          border
+          label="还库数量:"
+          placeholder="请输入数量"
+          type="digit"
+          name="pattern"
+          ref="countRef"
+          class="count-input"
+          @keydown.enter="onCountTask"
+          label-width="70px"
+          label-align="center"
+          :rules="[{ pattern, message: '请输入正确数量' }]"
+          autocomplete="off"
+        >
+<!--          <template #button>-->
+<!--            <div class="completion" @click="moveCount=model.qty">全部</div>-->
+<!--          </template>-->
+        </van-field>
+        <div class="tips" v-if="model['customerId']">
+          <van-row>
+            <van-col span="12">
+                <div>货&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;主:{{model.customerId}}</div>
+                <div>生产日期:{{model.productionDate || '--'}}</div>
+                <div>属&nbsp;&nbsp;性&nbsp;&nbsp;仓:{{model.attributeWarehouse}}</div>
+                <div>质量状态:{{model.quality}}</div>
+            </van-col>
+            <van-col span="12">
+                <div>失效日期:{{model.expirationDate || '--'}}</div>
+                <div>分配数量:{{model.qtyAllocated }}</div>
+                <div style="color: #0077ff;cursor: pointer;text-decoration: underline" @click="moveCount=model.availableQty">
+                  可还数量:<span >{{model.availableQty }}</span>
+                </div>
+            </van-col>
+          </van-row>
+        </div>
+      </van-form>
+    </van-dialog>
+  </div>
+</template>
+
+<script setup>
+import { onMounted, onUnmounted, ref, computed } from 'vue'
+import { useRouter,useRoute } from 'vue-router'
+import { useStore } from '@/store/modules/user'
+import { androidFocus, getHeader, goBack, scanError, scanSuccess } from '@/utils/android'
+import { closeListener, openListener, scanInit } from '@/utils/keydownListener'
+import { getInventory, getInventoryList, movementReturn } from '@/api/check/index'
+import InputBarcode from '@/views/outbound/picking/components/InputBarcode.vue'
+import { closeLoading, showLoading } from '@/utils/loading'
+import nodataUrl from '@/assets/nodata.png'
+import { showNotify, showToast } from 'vant'
+import { barcodeToUpperCase } from '@/utils/dataType.js'
+const router = useRouter()
+const route = useRoute()
+const store = useStore()
+try {
+  getHeader()
+  androidFocus()
+} catch (error) {
+  router.push('/login')
+}
+const warehouse = store.warehouse
+
+const pattern=/^[1-9]\d*$/
+// 容器号和扫描类型的状态
+const containerNo = ref(route.query.code)
+//输入框组件类型
+const inputBarcodeType = ref('')
+//扫描类型
+const scanType = ref(1)
+//输入框组件ref
+const inputBarcodeRef = ref(null)
+//可移动库存
+const moveList=ref([])
+//在库总库存
+const totalList=ref([])
+const searchRef=ref(null)
+//扫描条码
+const searchBarcode=ref('')
+//扫描库位
+const location=ref('')
+//
+const model=ref({})
+const countRef=ref(null)
+const back=ref(true)
+// 页面初始化
+onMounted(() => {
+  openListener()
+  scanInit(_handlerScan)
+  loadData()
+})
+//切换模式
+const actions = [
+  { name: '放弃', key: 'task' }
+]
+const modeTrueFalseBy = ref(false)
+const onClickRightIcon = () => {
+  modeTrueFalseBy.value = true
+}
+
+// 设置容器号
+const setBarcode = (code) => {
+  if (inputBarcodeType.value === 'barcode') {
+    _handlerScan(code)
+    return
+  }
+  const checkContainer = `FJ-${warehouse}-`
+  if (!code.includes(checkContainer)) {
+    scanError()
+    setTimeout(()=>{
+      inputBarcodeRef.value?.show('', '请扫描反拣容器', '扫描容器不是反拣容器,请重新扫描')
+    },300)
+    return
+  }
+  scanSuccess()
+  scanType.value = 2
+  containerNo.value = code
+  searchBarcode.value=''
+  moveList.value=''
+  location.value=''
+  // if(searchBarcode.value){
+  //   _getInventoryList(searchBarcode.value)
+  //   location.value=''
+  // }
+}
+const _setContainerNo=()=>{
+  inputBarcodeType.value=''
+  back.value=false
+  inputBarcodeRef.value?.show('', '请扫描反拣容器')
+}
+
+// 扫描条码监听
+const _handlerScan = (code) => {
+  console.log(code)
+  if (scanType.value === 2) {
+    setTimeout(()=>{
+      _getInventoryList(code)
+    },200)
+  }else if(scanType.value === 3){
+    const matchedItem = totalList.value.find((item) => barcodeToUpperCase(item.location) === barcodeToUpperCase(code))
+    location.value = matchedItem ? matchedItem.location : barcodeToUpperCase(code)
+    scanSuccess()
+    scanType.value = 4
+  }
+}
+
+// 获取库存数据
+const _getInventoryList = async (barcode) => {
+  const data = { warehouse, location: containerNo.value, barcode }
+  try {
+    showLoading()
+    const res = await getInventoryList(data)
+    closeLoading()
+    moveList.value = res.data
+    if (res.data.length === 0) {
+      scanError()
+      searchBarcode.value = ''
+      showNotify({ duration: 5000, message: `条码:${barcode},未找到可还库库存,请检查条码!` })
+      return
+    }
+    scanSuccess()
+    searchBarcode.value= res.data[0].sku
+    const params={ warehouse, barcode,locationRegexp:'^(?!STAGE_|SORTATION_|REVERSEPICK_|FJ-|TRANSFER_).*$',queryLocationInfo:true }
+    if(barcode==='') return
+    getInventory(params).then(res=>{
+      totalList.value=res.data
+    })
+    scanType.value=3
+  } catch (err) {
+    closeLoading()
+    console.error(err)
+  }
+}
+
+//移动数量
+const moveCount=ref('')
+//移动弹框
+const moveStockTrueFalseBy=ref(false)
+//还库
+const onMove=(item)=>{
+  if(searchBarcode.value===''){
+    scanError()
+    showToast({duration:5000,message:'请扫描商品条码'})
+    return
+  }
+  if(location.value===''){
+    scanError()
+    showToast({duration:5000,message:'请扫描还库库位'})
+    return
+  }
+  model.value=item
+  moveCount.value=''
+  moveStockTrueFalseBy.value=true
+  setTimeout(()=>{
+    countRef.value?.focus()
+  },300)
+}
+/**
+ * 确认还库
+ * @param action
+ */
+const  beforeClose= (action) =>
+  new Promise((resolve) => {
+    if(action==='confirm'){
+      if(moveCount.value==''){
+        scanError()
+        showToast({duration:5000,message:'请输入还库数量'})
+        return resolve(false)
+      }
+      if(Number(moveCount.value)>model.value.availableQty){
+        scanError()
+        showToast({duration:5000,message:'还库数量不能大于总数量'+model.value.availableQty})
+        return resolve(false)
+      }
+      moveStockTrueFalseBy.value=false
+      resolve(true)
+      createMoveStock()
+    }
+    resolve(true)
+  });
+const onCountTask=()=>{
+  if(moveCount.value==''){
+    scanError()
+    showToast({duration:5000,message:'请输入还库数量'})
+    return
+  }
+  if(Number(moveCount.value)>model.value.availableQty){
+    scanError()
+    showToast({duration:5000,message:'还库数量不能大于总数量'+model.value.availableQty})
+    return
+  }
+  moveStockTrueFalseBy.value=false
+  createMoveStock()
+}
+//移动库存
+const  createMoveStock=()=>{
+  const {warehouseId,customerId,lotNum,sku,locationId}=model.value
+  const data={
+    warehouse:warehouseId,owner:customerId,lotNum,sku,
+    quantity:moveCount.value,
+    fmLocation:locationId,
+    toLocation:location.value
+  }
+  showLoading()
+  movementReturn(data).then(res=>{
+    scanSuccess()
+    showToast({duration:3000,message:'操作成功'})
+    if(moveList.value.length===1 && model.value.availableQty==moveCount.value){
+      scanType.value=2
+      searchBarcode.value=''
+      location.value=''
+      moveList.value=[]
+      totalList.value=[]
+    }else {
+      location.value=''
+      _getInventoryList(searchBarcode.value)
+    }
+  }).catch(err=>{
+    scanError()
+  }).finally(_=>{
+    closeLoading()
+  })
+}
+
+// 提示文本根据扫描类型返回
+const tips = computed(() => {
+  switch (scanType.value) {
+    case 1:
+      return '请扫描容器号'
+    case 2:
+      return '请扫描商品条码'
+    case 3:
+      return '请扫描还库库位'
+    case 4:
+      return '请执行还库操作'
+    default:
+      return ''
+  }
+})
+const getClass = (item) => {
+  // if (moveList.value.length === 1) {
+  //   const currentMove = moveList.value[0]
+  //   if (item.location === location.value) {
+  //     return 'location-active'
+  //   }
+  //   if (item.lotAtt01 === currentMove.productionDate && item.lotAtt02 === currentMove.expirationDate) {
+  //     return 'barcode-active'
+  //   }
+  // }
+// locationUsage 库位使用类型:拣货库位(PC/CS/EA)、存储位(RS)、过渡库位(ST)、其他库位
+  if(item.locationUsage==='PC' || item.locationUsage==='CS' || item.locationUsage==='EA' ){
+    return 'pricking-active'
+  }else if(item.locationUsage==='RS' ){
+    return 'stock-active'
+  }else if(item.locationUsage==='ST' ){
+    return 'virtual-active'
+  }
+  return ''
+};
+const onSelectMode = async (value) => {
+
+}
+
+// 数据刷新
+const loadData = () => {
+  if(searchBarcode.value){
+    _getInventoryList(searchBarcode.value)
+    return
+  }
+  inputBarcodeType.value = ''
+  if (!containerNo.value) {
+    inputBarcodeRef.value?.show('', '请扫描反拣容器号')
+    return
+  }
+  scanType.value = 2
+}
+
+onUnmounted(() => {
+  closeListener()
+})
+
+window.onRefresh = loadData
+</script>
+
+<style scoped lang="scss">
+.container {
+  .move-stock {
+    .code {
+      background: #e9f4ff;
+      box-sizing: border-box;
+      padding: 8px 0;
+    }
+    .code-title {
+      display: flex;
+      justify-content: space-between;
+      padding: 0 15px 8px 15px;
+    }
+    .code-input {
+      ::v-deep(.van-search) {
+        padding: 0;
+        font-size: 16px;
+      }
+      ::v-deep(.van-search__field) {
+        border-bottom: 2px solid #ffffff;
+        height: 50px;
+        display: flex;
+        align-items: center;
+      }
+      ::v-deep(.van-search__content) {
+        background: #fff;
+        height: 50px;
+        display: flex;
+        align-items: center;
+      }
+      ::v-deep(.van-field__control) {
+        font-size: 16px;
+        height: 50px;
+        line-height: 50px;
+      }
+      .search-input-barcode {
+        ::v-deep(.van-search__field) {
+          border-bottom: 2px solid #0077ff;
+          z-index: 2;
+        }
+      }
+    }
+    .code-tips {
+      color: #ed6a0c;
+      flex: 1;
+    }
+    .code-count {
+      font-size: 16px;
+      font-weight: bold;
+      span {
+        color: #0077ff;
+      }
+    }
+    .nav-right {
+      padding: 14px 0 12px 5px;
+    }
+    .move-stock-list {
+      width: 100%;
+      overflow-y: auto;
+      max-height: 280px;
+      min-height: 100px;
+      .move-button {
+        background: #1989fa;
+        color: #fff;
+        width: 100%;
+        height: 30px;
+        font-size: 14px;
+        line-height: 30px;
+        font-weight: bold;
+      }
+      .task-table,
+      .task-table-bin,
+      .task-table-box {
+        width: 100%;
+        table-layout: fixed;
+        border-collapse: collapse;
+        font-size: 13px;
+      }
+      .task-table th,
+      .task-table-bin th,
+      .task-table td,
+      .task-table-bin td,
+      .task-table-box th,
+      .task-table-box td {
+        text-align: center;
+        border: 1px solid #ccc;
+        word-wrap: break-word;
+        word-break: break-all;
+      }
+      .task-table thead,
+      .task-table-bin thead,
+      .task-table-box thead {
+        background-color: #3f8dff;
+        position: sticky;
+        top: 0;
+        color: white;
+        font-size: 13px;
+      }
+      .task-table-bin thead {
+        background-color: #3f8dff;
+      }
+      .task-table-bin tbody {
+        background: #cde7ff;
+      }
+      .task-table tbody tr.pricking-active {
+        background-color: #d6f9e7;
+      }
+      .task-table tbody tr.stock-active {
+        background-color: #fffadd;
+      }
+      .task-table tbody tr.virtual-active {
+        background-color: #cacaca;
+      }
+    }
+    .move-stock-content {
+      margin-bottom: 10px;
+
+      .compact-table {
+        width: 100%;
+        border-collapse: collapse;
+        margin: 0;
+        font-size: 14px;
+        line-height: 1.2;
+        border: 1px solid #ccc;
+
+        td {
+          padding: 8px 12px;
+          border: 1px solid #ccc;
+          background: transparent;
+          text-align: center;
+        }
+
+        td:first-child {
+          color: #333;
+          font-size: 25px;
+        }
+
+        td:last-child {
+          color: #e63535;
+          font-size: 50px;
+
+        }
+      }
+    }
+  }
+}
+.count-input {
+  ::v-deep(.van-field__value) {
+    border-bottom: 2px solid #0077ff;
+    font-size: 16px;
+  }
+}
+.completion {
+  text-align: right;
+  font-size: 14px;
+  line-height: 35px;
+  color: #0077ff;
+  padding: 0 10px;
+  cursor: pointer;
+  text-decoration: underline;
+}
+.tips {
+  font-size: 13px;
+  text-align: left;
+  padding: 5px 15px;
+}
+</style>