From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目

---
 src/views/mall/trade/delivery/pickUpOrder/index.vue |  436 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 436 insertions(+), 0 deletions(-)

diff --git a/src/views/mall/trade/delivery/pickUpOrder/index.vue b/src/views/mall/trade/delivery/pickUpOrder/index.vue
new file mode 100644
index 0000000..5d4fc4f
--- /dev/null
+++ b/src/views/mall/trade/delivery/pickUpOrder/index.vue
@@ -0,0 +1,436 @@
+<template>
+  <doc-alert title="銆愪氦鏄撱�戜氦鏄撹鍗�" url="https://doc.iocoder.cn/mall/trade-order/" />
+  <doc-alert title="銆愪氦鏄撱�戣喘鐗╄溅" url="https://doc.iocoder.cn/mall/trade-cart/" />
+
+  <!-- 鎼滅储 -->
+  <ContentWrap>
+    <el-form
+      ref="queryFormRef"
+      :inline="true"
+      :model="queryParams"
+      class="-mb-15px"
+      label-width="68px"
+    >
+      <el-form-item label="鍒涘缓鏃堕棿" prop="createTime">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-280px"
+          end-placeholder="鑷畾涔夋椂闂�"
+          start-placeholder="鑷畾涔夋椂闂�"
+          type="daterange"
+          value-format="YYYY-MM-DD HH:mm:ss"
+        />
+      </el-form-item>
+      <el-form-item label="鑷彁闂ㄥ簵" prop="pickUpStoreIds">
+        <el-select
+          v-model="queryParams.pickUpStoreIds"
+          class="!w-280px"
+          placeholder="鍏ㄩ儴"
+          @change="handleQuery"
+        >
+          <el-option
+            v-for="item in pickUpStoreList"
+            :key="item.id"
+            :label="item.name"
+            :value="item.id"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鑱氬悎鎼滅储">
+        <el-input
+          v-show="true"
+          v-model="queryParams[queryType.queryParam]"
+          class="!w-280px"
+          clearable
+          placeholder="璇疯緭鍏�"
+          :type="queryType.queryParam === 'userId' ? 'number' : 'text'"
+        >
+          <template #prepend>
+            <el-select
+              v-model="queryType.queryParam"
+              class="!w-110px"
+              placeholder="鍏ㄩ儴"
+              @change="inputChangeSelect"
+            >
+              <el-option
+                v-for="dict in dynamicSearchList"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </template>
+        </el-input>
+      </el-form-item>
+      <el-form-item>
+        <el-button @click="handleQuery">
+          <Icon class="mr-5px" icon="ep:search" />
+          鎼滅储
+        </el-button>
+        <el-button @click="resetQuery">
+          <Icon class="mr-5px" icon="ep:refresh" />
+          閲嶇疆
+        </el-button>
+        <el-button
+          @click="handlePickup"
+          type="success"
+          plain
+          v-hasPermi="['trade:order:pick-up']"
+          :disabled="isUse"
+        >
+          <Icon class="mr-5px" icon="ep:check" />
+          鏍搁攢
+        </el-button>
+        <el-button type="primary" @click="connectToSerialPort" :disabled="serialPort || isUse">
+          杩炴帴鎵弿鏋�
+        </el-button>
+        <el-button type="danger" @click="cutPort" :disabled="!serialPort || isUse">
+          鏂紑鎵弿鏋�
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </ContentWrap>
+
+  <!-- 缁熻鍗$墖 -->
+  <el-row :gutter="16" class="summary">
+    <el-col :sm="6" :xs="12" v-loading="loading">
+      <SummaryCard
+        title="璁㈠崟鏁伴噺"
+        icon="icon-park-outline:transaction-order"
+        icon-color="bg-blue-100"
+        icon-bg-color="text-blue-500"
+        :value="summary?.orderCount || 0"
+      />
+    </el-col>
+    <el-col :sm="6" :xs="12" v-loading="loading">
+      <SummaryCard
+        title="璁㈠崟閲戦"
+        icon="streamline:money-cash-file-dollar-common-money-currency-cash-file"
+        icon-color="bg-purple-100"
+        icon-bg-color="text-purple-500"
+        prefix="锟�"
+        :decimals="2"
+        :value="fenToYuan(summary?.orderPayPrice || 0)"
+      />
+    </el-col>
+    <el-col :sm="6" :xs="12" v-loading="loading">
+      <SummaryCard
+        title="閫�娆惧崟鏁�"
+        icon="heroicons:receipt-refund"
+        icon-color="bg-yellow-100"
+        icon-bg-color="text-yellow-500"
+        :value="summary?.afterSaleCount || 0"
+      />
+    </el-col>
+    <el-col :sm="6" :xs="12" v-loading="loading">
+      <SummaryCard
+        title="閫�娆鹃噾棰�"
+        icon="ri:refund-2-line"
+        icon-color="bg-green-100"
+        icon-bg-color="text-green-500"
+        prefix="锟�"
+        :decimals="2"
+        :value="fenToYuan(summary?.afterSalePrice || 0)"
+      />
+    </el-col>
+  </el-row>
+
+  <!-- 鍒楄〃 -->
+  <ContentWrap>
+    <el-table v-loading="loading" :data="list">
+      <el-table-column label="璁㈠崟鍙�" align="center" prop="no" min-width="180" />
+      <el-table-column label="鐢ㄦ埛淇℃伅" align="center" prop="user.nickname" min-width="80" />
+      <el-table-column
+        label="鎺ㄨ崘浜轰俊鎭�"
+        align="center"
+        prop="brokerageUser.nickname"
+        min-width="100"
+      />
+      <el-table-column label="鍟嗗搧淇℃伅" align="center" prop="spuName" min-width="300">
+        <template #default="{ row }">
+          <div class="flex items-center" v-for="item in row.items" :key="item.id">
+            <el-image
+              :src="item.picUrl"
+              class="mr-10px h-30px w-30px flex-shrink-0"
+              :preview-src-list="[item.picUrl]"
+              preview-teleported
+            />
+            <span class="mr-10px">{{ item.spuName }}</span>
+            <div class="flex flex-col flex-wrap gap-1">
+              <el-tag
+                v-for="property in item.properties"
+                :key="property.propertyId"
+                class="mr-10px"
+              >
+                {{ property.propertyName }}: {{ property.valueName }}
+              </el-tag>
+              <span>{{ floatToFixed2(item.price) }} 鍏� x {{ item.count }}</span>
+            </div>
+          </div>
+        </template>
+      </el-table-column>
+      <el-table-column
+        label="瀹炰粯閲戦(鍏�)"
+        align="center"
+        prop="payPrice"
+        min-width="110"
+        :formatter="fenToYuanFormat"
+      />
+      <el-table-column label="鏍搁攢鍛�" align="center" prop="storeStaffName" min-width="70" />
+      <el-table-column label="鏍搁攢闂ㄥ簵" align="center" prop="pickUpStoreId" min-width="80">
+        <template #default="{ row }">
+          {{ pickUpStoreList.find((p) => p.id === row.pickUpStoreId)?.name }}
+        </template>
+      </el-table-column>
+      <el-table-column label="鏀粯鐘舵��" align="center" prop="payStatus" min-width="80">
+        <template #default="{ row }">
+          <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.payStatus || false" />
+        </template>
+      </el-table-column>
+      <el-table-column align="center" label="璁㈠崟鐘舵��" prop="status" width="120">
+        <template #default="{ row }">
+          <dict-tag :type="DICT_TYPE.TRADE_ORDER_STATUS" :value="row.status" />
+        </template>
+      </el-table-column>
+      <el-table-column
+        label="涓嬪崟鏃堕棿"
+        align="center"
+        prop="createTime"
+        min-width="170"
+        :formatter="dateFormatter"
+      />
+    </el-table>
+    <!-- 鍒嗛〉 -->
+    <Pagination
+      v-model:limit="queryParams.pageSize"
+      v-model:page="queryParams.pageNo"
+      :total="total"
+      @pagination="getList"
+    />
+  </ContentWrap>
+
+  <!-- 鍚勭鎿嶄綔鐨勫脊绐� -->
+  <OrderPickUpForm ref="pickUpForm" @success="getList" />
+</template>
+
+<script lang="ts" setup>
+import type { FormInstance } from 'element-plus'
+import * as TradeOrderApi from '@/api/mall/trade/order'
+import * as PickUpStoreApi from '@/api/mall/trade/delivery/pickUpStore'
+import { DICT_TYPE } from '@/utils/dict'
+import { fenToYuan, floatToFixed2 } from '@/utils'
+import { fenToYuanFormat } from '@/utils/formatter'
+import SummaryCard from '@/components/SummaryCard/index.vue'
+import { dateFormatter } from '@/utils/formatTime'
+import { DeliveryTypeEnum } from '@/utils/constants'
+import { TradeOrderSummaryRespVO } from '@/api/mall/trade/order'
+import { DeliveryPickUpStoreVO } from '@/api/mall/trade/delivery/pickUpStore'
+import OrderPickUpForm from '@/views/mall/trade/order/form/OrderPickUpForm.vue'
+import { ref, onMounted } from 'vue'
+import { useUserStore } from '@/store/modules/user'
+const message = useMessage() // 娑堟伅寮圭獥
+
+const port = ref('')
+const ports = ref([])
+const reader = ref('')
+
+defineOptions({ name: 'PickUpOrder' })
+
+const loading = ref(true) // 鍒楄〃鐨勫姞杞戒腑
+const total = ref(2) // 鍒楄〃鐨勬�婚〉鏁�
+const list = ref<TradeOrderApi.OrderVO[]>([]) // 鍒楄〃鐨勬暟鎹�
+const queryFormRef = ref<FormInstance>() // 鎼滅储鐨勮〃鍗�
+const INIT_QUERY_PARAMS = {
+  // 椤垫暟
+  pageNo: 1,
+  // 姣忛〉鏄剧ず鏁伴噺
+  pageSize: 10,
+  // 鍒涘缓鏃堕棿
+  createTime: undefined,
+  // 閰嶉�佹柟寮�
+  deliveryType: DeliveryTypeEnum.PICK_UP.type,
+  // 鑷彁闂ㄥ簵
+  pickUpStoreIds: -1
+} // 鍒濆琛ㄥ崟鍙傛暟
+
+const queryParams = ref({ ...INIT_QUERY_PARAMS }) // 琛ㄥ崟鎼滅储
+const queryType = reactive({ queryParam: 'no' }) // 璁㈠崟鎼滅储绫诲瀷 queryParam
+const summary = ref<TradeOrderSummaryRespVO>() // 璁㈠崟缁熻鏁版嵁
+
+const serialPort = ref(false) // 鏄惁杩炴帴鎵爜鏋�
+const isUse = ref(true) // 鏄惁鍙牳閿�
+
+// 璁㈠崟鑱氬悎鎼滅储 select 绫诲瀷閰嶇疆锛堝姩鎬佹悳绱級
+const dynamicSearchList = ref([
+  { value: 'no', label: '璁㈠崟鍙�' },
+  { value: 'userId', label: '鐢ㄦ埛 UID' },
+  { value: 'userNickname', label: '鐢ㄦ埛鏄电О' },
+  { value: 'userMobile', label: '鐢ㄦ埛鐢佃瘽' }
+])
+/**
+ * 鑱氬悎鎼滅储鍒囨崲鏌ヨ瀵硅薄鏃惰Е鍙�
+ * @param val
+ */
+const inputChangeSelect = (val: string) => {
+  dynamicSearchList.value
+    .filter((item) => item.value !== val)
+    ?.forEach((item) => {
+      // 娓呴櫎闆嗗悎鎼滅储鏃犵敤灞炴��
+      if (queryParams.value.hasOwnProperty(item.value)) {
+        delete queryParams.value[item.value]
+      }
+    })
+}
+
+/** 鏌ヨ鍒楄〃 */
+const getList = async () => {
+  loading.value = true
+  try {
+    // 缁熻
+    summary.value = await TradeOrderApi.getOrderSummary(unref(queryParams))
+    // 鍒嗛〉
+    const data = await TradeOrderApi.getOrderPage(unref(queryParams))
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = async () => {
+  queryParams.value.pageNo = 1
+  await getList()
+}
+
+/** 閲嶇疆鎸夐挳鎿嶄綔 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields()
+  queryParams.value = { ...INIT_QUERY_PARAMS }
+  if (pickUpStoreList.value.length > 0) {
+    queryParams.value.pickUpStoreIds = pickUpStoreList.value[0].id
+  }
+  handleQuery()
+}
+
+/** 鑷彁闂ㄥ簵绮剧畝鍒楄〃 */
+const pickUpStoreList = ref<DeliveryPickUpStoreVO[]>([])
+const getPickUpStoreList = async () => {
+  pickUpStoreList.value = await PickUpStoreApi.getSimpleDeliveryPickUpStoreList()
+  // 绉婚櫎鑷繁鏃犳硶鏍搁攢鐨勯棬搴�
+  const userId = useUserStore().getUser.id
+  pickUpStoreList.value = pickUpStoreList.value.filter((item) =>
+    item.verifyUserIds?.includes(userId)
+  )
+}
+
+/** 鏄剧ず鏍搁攢琛ㄥ崟 */
+const pickUpForm = ref()
+const handlePickup = () => {
+  pickUpForm.value.open()
+}
+
+/** 杩炴帴鎵爜鏋� */
+const connectToSerialPort = async () => {
+  try {
+    // 鍒ゆ柇娴忚鍣ㄦ敮鎸佷覆鍙i�氫俊
+    if (
+      'serial' in navigator &&
+      navigator.serial != null &&
+      typeof navigator.serial === 'object' &&
+      'requestPort' in navigator.serial
+    ) {
+      // 鎻愮ず鐢ㄦ埛閫夋嫨涓�涓覆鍙�
+      port.value = await navigator.serial.requestPort()
+    } else {
+      message.error('娴忚鍣ㄤ笉鏀寔鎵爜鏋繛鎺ワ紝璇锋洿鎹㈡祻瑙堝櫒閲嶈瘯')
+      return
+    }
+
+    // 鑾峰彇鐢ㄦ埛涔嬪墠鎺堜簣璇ョ綉绔欒闂潈闄愮殑鎵�鏈変覆鍙c��
+    ports.value = await navigator.serial.getPorts()
+
+    // console.log(port.value, ports.value);
+    // console.log(port.value)
+    // 绛夊緟涓插彛鎵撳紑
+    await port.value.open({ baudRate: 9600, dataBits: 8, stopBits: 2 })
+
+    // console.log(typeof port.value);
+    message.success('鎴愬姛杩炴帴鎵爜鏋�')
+    serialPort.value = true
+    // readData(port.value);
+    readData()
+  } catch (error) {
+    // 澶勭悊杩炴帴涓插彛鍑洪敊鐨勬儏鍐�
+    console.log('Error connecting to serial port:', error)
+  }
+}
+
+/** 鐩戝惉鎵爜鏋緭鍏� */
+const readData = async () => {
+  reader.value = port.value.readable.getReader()
+  let data = '' //鎵爜鏁版嵁
+  // 鐩戝惉鏉ヨ嚜涓插彛鐨勬暟鎹�
+  while (true) {
+    const { value, done } = await reader.value.read()
+    if (done) {
+      // 鍏佽绋嶅悗鍏抽棴涓插彛
+      reader.value.releaseLock()
+      break
+    }
+    // 鑾峰彇鍙戦�佺殑鏁版嵁
+    const serialData = new TextDecoder().decode(value)
+    data = `${data}${serialData}`
+    if (serialData.includes('\r')) {
+      //璇诲彇缁撴潫
+      let codeData = data.replace('\r', '')
+      data = '' //娓呯┖涓嬫璇诲彇涓嶄細鍙犲姞
+      console.log(`浜岀淮鐮佹暟鎹�:${codeData}`)
+      //澶勭悊鎷垮埌鏁版嵁閫昏緫
+      pickUpForm.value.open(codeData)
+    }
+  }
+}
+
+/** 鏂紑鎵爜鏋� */
+const cutPort = async () => {
+  if (port.value !== '') {
+    await reader.value.cancel()
+    await port.value.close()
+    port.value = ''
+    console.log('鏂紑鎵爜鏋繛鎺�')
+    message.success('宸叉垚鍔熸柇寮�鎵爜鏋繛鎺�')
+    serialPort.value = false
+  } else {
+    message.warning('璇峰厛杩炴帴鎴栨墦寮�鎵爜鏋�')
+  }
+}
+
+/** 鍒濆鍖� **/
+onMounted(async () => {
+  await getPickUpStoreList()
+  if (pickUpStoreList.value.length === 0) {
+    message.error('褰撳墠鐧诲綍浜烘病缁戝畾浠讳綍鑷彁鐐�')
+    loading.value = false
+    isUse.value = true
+    return
+  }
+
+  // 鏌ヨ
+  queryParams.value.pickUpStoreIds = pickUpStoreList.value[0].id
+  isUse.value = false
+  await getList()
+})
+</script>
+<style lang="scss" scoped>
+:deep(.order-table-col > .cell) {
+  padding: 0;
+}
+
+.summary {
+  .el-col {
+    margin-bottom: 1rem;
+  }
+}
+</style>

--
Gitblit v1.8.0