فهرست منبع

Merge remote-tracking branch 'origin/testing' into testing

zhaohuanhuan 8 ماه پیش
والد
کامیت
554c222c69
2فایلهای تغییر یافته به همراه43 افزوده شده و 945 حذف شده
  1. 31 0
      src/utils/android.ts
  2. 12 945
      src/views/piece/dashboard/index.vue

+ 31 - 0
src/utils/android.ts

@@ -103,3 +103,34 @@ export function scanError(){
 
   }
 }
+
+export function openCamera(){
+  try {
+    // @ts-ignore
+    const path = window.android.openCamera()
+    console.log(path)
+    return path
+  }catch (e){
+
+  }
+}
+
+export function openGallery(){
+  try {
+    // @ts-ignore
+    const header = window.android.openGallery()
+    console.log(header)
+  }catch (e){
+
+  }
+}
+
+export function openImageEditor(imagePath: string){
+  try {
+    // @ts-ignore
+    const header = window.android.openImageEditor(imagePath)
+    console.log(header)
+  }catch (e){
+
+  }
+}

+ 12 - 945
src/views/piece/dashboard/index.vue

@@ -1,959 +1,26 @@
 <template>
-  <van-overlay :show="!isOnline">
-    <div class="wrapper">
-      <!-- 断网提示(固定在顶部) -->
-      <div v-if="!isOnline" class="network-alert offline">
-        ⚠️ 网络已断开,请检查您的网络连接!
-      </div>
-      <!-- 网络恢复提示 -->
-      <Transition name="fade">
-        <div v-if="showReconnected" class="network-alert online">
-          ✅ 网络已恢复
-        </div>
-      </Transition>
-    </div>
-  </van-overlay>
-  <van-row class="container">
-    <van-col span="6" class="user-panel">
-      <div class="user-header">
-        <h3>用户信息</h3>
-      </div>
-
-      <div class="info-grid">
-<!--        <div class="info-item">-->
-<!--          <div class="info-label">用户ID</div>-->
-<!--          <div class="info-value">{{ userInfo.userId }}</div>-->
-<!--        </div>-->
-
-        <div class="info-item">
-          <div class="info-label">用户姓名</div>
-          <div class="info-value" :style="{ color: !userInfo.name ? 'red' : '#1e1f1f' }">{{ userInfo.name || '请登录' }}</div>
-        </div>
-
-        <div class="info-item">
-          <div class="info-label">MAC地址</div>
-          <div class="info-value">{{ mac }}</div>
-        </div>
-
-        <div class="info-item">
-          <div class="info-label">仓库</div>
-          <div class="info-value">{{ frogPosition.warehouse }}</div>
-        </div>
-
-        <div class="info-item">
-          <div class="info-label">位置编号</div>
-          <div class="info-value">{{ frogPosition.code }}</div>
-        </div>
-
-        <div class="info-item">
-          <div class="info-label">用途类型</div>
-          <div class="info-value">{{ frogPosition.type }}</div>
-        </div>
-      </div>
-
-      <div class="error-section">
-        <div class="error-display">
-          <div class="error-label" @click="logout">退出登录</div>
-          <!--          <div class="error-count">{{ errNum }}</div>-->
-        </div>
-      </div>
-
-    </van-col>
-    <van-col span="18" class="table-container">
-      <van-cell-group class="custom-cell-group">
-        <van-cell title="系统提示:" :value="message" :value-class="{'success-message': message && message.includes('扫描成功')}"/>
-      </van-cell-group>
-
-      <div class="waterfall-table">
-        <!-- 固定表头 -->
-        <div class="table-header">
-          <div class="col index">序号</div>
-          <div class="col time">时间</div>
-          <div class="col operator">操作人</div>
-          <div class="col content">操作内容</div>
-        </div>
-
-        <van-pull-refresh
-          ref="pullRefreshRef"
-          v-model="refreshing"
-          success-text="刷新成功"
-          @refresh="onRefresh"
-          class="table-body"
-        >
-          <!-- 表格主体 -->
-          <van-list
-            v-model:loading="loading"
-            :finished="finished"
-            finished-text="没有更多了"
-            @load="onLoad">
-            <div
-              v-for="(item, index) in list"
-              :key="item.id"
-              class="table-row"
-            >
-              <div class="col index">{{ index + 1 }}</div>
-              <div class="col time">{{ item.operationTime.replace(/^\d{4}-/, '') }}</div>
-              <div class="col operator">{{ item.operatorName }}</div>
-              <div class="col content">{{ item.deliveryNo }}</div>
-            </div>
-            <van-back-top @click="scrollTop"/>
-          </van-list>
-        </van-pull-refresh>
-      </div>
-    </van-col>
-  </van-row>
-  <van-button class="add" icon="setting-o" type="primary" @click="_openSetting" />
-  <van-sticky>
-    <van-dialog
-      v-model:show="setting.show"
-      title="设置"
-      class="setting-dialog"
-      show-cancel-button
-      :before-close="_verifyMac"
-      @confirm="_saveMac"
-      @closed="_closeSetting"
-      width="380px">
-
-      <van-notice-bar
-        wrapable
-        left-icon="volume-o"
-        :scrollable="false"
-        :text="hintMessage"
-      />
-
-      <van-cell-group inset>
-        <van-field
-          v-model="setting.mac"
-          label="MAC地址"
-          placeholder="请输入MAC地址"
-        />
-        <van-field
-          v-model="setting.password"
-          type="password"
-          label="密码"
-          placeholder="设置密码"
-        />
-      </van-cell-group>
-
-      <van-notice-bar color="#1989fa" background="#ecf9ff" @click="checkUpdate"
-                      style="font-size: 16px; padding-left: 10px" left-icon="info-o">
-        版本号:{{ versionName }} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(点击检查更新)
-      </van-notice-bar>
-    </van-dialog>
-  </van-sticky>
+  <button @click="_openCamera">打开相机</button>
+  <button @click="_openGallery">打开相册选择图片并返回路径</button>
+  <button @click="_openImageEditor">打开图片编辑器</button>
 </template>
 
 <script setup>
-import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
-import { closeListener, openListener, scanInit } from '@/utils/keydownListener'
-import { scanSuccess, scanError } from '@/utils/android'
-import { getVersionName, checkUpdate, saveUserId, getUserId, scanRepeat, saveMacAddress, listErrRecords, reLoginTip,
-   readMacAddress, pageDelivery, addDelivery, isDeliveryNoExists, markAsPushed, getErrRecordsCount, removeUserId, scanErr } from '@/utils/androidPiece'
-import { showLoadingToast, showNotify } from 'vant'
-import { getUserIdByCert, getUserNameById } from '@/api/login/index'
-import { receive, getScanDriverInfo } from '@/api/scan/index'
-import { formatDateTime } from '@/utils/date'
-
-// 在输入对话框或界面中添加提示文本
-const hintMessage = ref(`请前往:设置 → 关于平板电脑 → 设备WLAN MAC 地址 长按复制并粘贴到此处。`);
-const mac = ref('')
-const userInfo = ref({
-  userId: '',
-  name: ''
-})
-const setting = ref({
-  show: false,
-  mac: '',
-  password: ''
-})
-const message = ref('')
-const list = ref([])
-const loading = ref(false)
-const finished = ref(false)
-const errNum = ref(0)
-const preDeliveryNo = ref('')
-
-// 小青蛙位置属性
-const frogPosition = ref({
-  warehouse: '',
-  type:'',
-  code:''
-})
-
-
-const isOnline = ref(navigator.onLine)
-// 更新网络状态
-const updateNetworkStatus = () => {
-  isOnline.value = navigator.onLine
-}
-
-// 退出登录
-const logout = () => {
-  if (!userInfo.value.userId) {
-    scanError()
-    showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请先登录!' });
-    return
-  }
-  userInfo.value = {}
-  removeUserId()
-  scanSuccess()
-  showNotify({ type: 'success', style: 'font-size: 30px !important;height:50px', message: '已退出登录!' });
-}
-
-// 网络提示
-const showReconnected = ref(false)
-let reconnectTimer = null
-watch(isOnline, (newVal, oldVal) => {
-  // 当网络从离线变为在线时
-  if (newVal && !oldVal) {
-    scanSuccess()
-    showReconnected.value = true
-
-    // 3秒后自动隐藏恢复提示
-    reconnectTimer = setTimeout(() => {
-      showReconnected.value = false
-    }, 3000)
-  }
-
-  // 当网络从在线变为离线时,隐藏恢复提示
-  if (!newVal && oldVal) {
-    scanError()
-    showReconnected.value = false
-  }
-})
-
-onUnmounted(() => {
-  window.removeEventListener('online', updateNetworkStatus)
-  window.removeEventListener('offline', updateNetworkStatus)
-  closeListener()
-})
-
-onMounted(() => {
-  window.addEventListener('online', updateNetworkStatus)
-  window.addEventListener('offline', updateNetworkStatus)
-
-  versionName.value = getVersionName()
-  mac.value = readMacAddress()
-  // 获取用户信息
-  if (!userInfo.value.userId) {
-    const userId = getUserId()
-    if (userId) {
-      userInfo.value.userId = userId
-      getUserName(userId)
-    }
-  }
-  // 获取机器位置信息
-  if (!frogPosition.value.warehouse && mac.value) {
-    getFrogPosition()
-  }
-
-  if (mac.value) {
-    _openScan()
-  } else {
-    _openSetting()
-  }
-  // ip
-  // fetchIP()
-  // err数量
-  errNum.value = getErrNum()
-})
-
-const getFrogPosition = () => {
-  getScanDriverInfo(mac.value).then(res => {
-    if (res && res.data) {
-      frogPosition.value.warehouse = res.data.warehouseCode
-      frogPosition.value.type = res.data.type
-      frogPosition.value.code = res.data.code
-    }
-  })
-}
-
-const _openScan = () => {
-  openListener()
-  setTimeout(() => {
-    scanInit(debounceScan)
-  },300)
-}
-
-const pushing = ref(false)
-const pullRefreshRef = ref(null)
-const scanDebounceTimeout = ref(null)
-
-const debounceScan = (code) => {
-  // 清除之前的防抖计时器
-  if (scanDebounceTimeout.value) {
-    clearTimeout(scanDebounceTimeout.value)
-  }
-
-  // 设置新的防抖计时器
-  scanDebounceTimeout.value = setTimeout(() => {
-    _handlerScan(code)
-  }, 300) // 300ms 防抖时间
-}
-const _handlerScan = (code) => {
-  code = fixDuplicateText(code)
-  // 校验扫描的是否为登录二维码
-  const regex = /\{"sign":"([^"]*)",\s*"identity":(\d+)\}/;
-  if (code !== null && regex.test(code)) {
-    const match = regex.exec(code)
-    const sign = match[1]
-    const identity = match[2]
-    getUserIdByCert({sign: sign, identity: identity}).then(res => {
-      if (res && res.data) {
-        userInfo.value.userId = res.data
-        getUserName(res.data)
-      } else {
-        showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '登录失败!' });
-      }
-    })
-  } else {
-    // 检查长度是否在11到25个字符之间
-    if (typeof code !== 'string' || code.length < 11 || code.length > 25) {
-      console.log(code)
-      scanErr()
-      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请扫描正确的快递单号!' });
-      return
-    }
-    // 数字0-9,大写字母A-Z,部分特殊字符(空格、! " % & ' ( ) * + , - . / : ; < = > ? _)
-    const code128BPattern = /^[\x20-\x7F]+$/;
-    // 检查是否只包含有效字符
-    if (!code128BPattern.test(code)) {
-      console.log(code)
-      scanErr()
-      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请扫描正确的快递单号!' });
-      return
-    }
-    scrollTop()
-    // 校验是否已登录
-    if (!userInfo.value.userId) {
-      scanError()
-      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请先登录!' });
-      return
-    }
-    // 校验是否为空
-    if (!code) {
-      scanErr()
-      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请先扫描快递单号!' });
-      return
-    }
-
-    if (pushing.value) {
-      scanErr()
-      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '正在提交中,请稍后扫描!' });
-      return
-    }
-    pushing.value =  true  // 请求状态锁
-
-    // 校验是否已扫描
-    if (list.value.some(item => item.code === code)) {
-      scanRepeat()
-      pushing.value = false
-      message.value = '该快递单已扫描!'
-      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '该快递单已扫描!' });
-      return
-    }
-
-    const exists = isDeliveryNoExists(code)
-    if (!exists) {
-      scanRepeat()
-      pushing.value = false
-      message.value = '该快递单已扫描!'
-      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '该快递单已扫描!' });
-      return
-    }
-
-    const toast = showLoadingToast({
-      message: '上传中...',
-      forbidClick: true,
-      duration: 0 // 禁止自动关闭
-    });
-    // 校验是否已存在
-    const currentTime = formatDateTime(new Date())
-    message.value = ''
-    const dto = {
-      deliveryNo: code,
-      machine: mac.value,
-      operator: userInfo.value.userId,
-      operationTime: currentTime,
-      operatorName: userInfo.value.name,
-      isPush: 1,
-      preDeliveryNo: preDeliveryNo.value,
-      version: versionName.value }
-
-    receive(dto).then(res => {
-      if (res && res.code === 200) {
-        const result = addDelivery(mac.value, code, userInfo.value.userId, userInfo.value.name)
-        if (result === -1) {
-          scanRepeat()
-          message.value = '该快递单已扫描!'
-          showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '该快递单已扫描!' });
-          return
-        }
-        if (result === -2) {
-          scanErr()
-          showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '添加失败,请联系开发人员!' });
-          return
-        }
-        preDeliveryNo.value = code
-        scanSuccess()
-        message.value = code + '扫描成功!'
-        list.value.unshift(dto)
-        showNotify({ type: 'success', style: 'font-size: 30px !important;height:50px', message: '扫描成功!' });
-      }
-    }).catch(err => {
-      if (err.code === 700) {
-        userInfo.value = {}
-        reLoginTip()
-      } else {
-        scanErr()
-      }
-      showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: `扫描失败!${err.message}` });
-    }).finally(() => {
-      toast.close();
-      pushing.value = false
-    })
-  }
-}
-
-const scrollTop = () => {
-  // 添加滚动到顶部的逻辑
-  nextTick(() => {
-    const el = pullRefreshRef.value?.$el;
-    if (el && el.scrollTo) {
-      el.scrollTo({ top: 0, behavior: 'smooth' });
-    } else if (el) {
-      // 回退方案
-      el.scrollTop = 0;
-    }
-  })
-}
-function fixDuplicateText(input) {
-  // 改进版正则表达式(支持任意字符且精确匹配完全重复)
-  const regex = /^(.+?)\1$/; // 非贪婪模式防止误匹配
-  const match = input.match(regex);
-  // 返回处理逻辑
-  return match ? match[1] : input;
-}
-
-
-// 在外部定义一个防抖函数映射表,用于跟踪每个单据的防抖状态
-const debounceMap = new Map();
-
-// 防抖函数封装
-const debounce = (func, wait = 500) => {
-  let timer;
-  return (...args) => {
-    clearTimeout(timer);
-    timer = setTimeout(() => {
-      func.apply(this, args);
-    }, wait);
-  };
-};
-
-// 修改后的推送函数
-const _rePush = (item) => {
-  if (!item || item.isPush === 1) return;
-  let status = false
-  showLoadingToast({
-    message: '上传中...',
-    forbidClick: true,
-    closeToast: status
-  });
-  // 初始化当前单据的防抖状态
-  if (!debounceMap.has(item.deliveryNo)) {
-    debounceMap.set(item.deliveryNo, {
-      isPushing: false,  // 请求状态锁
-      debouncedFn: debounce(() => {
-        const entry = debounceMap.get(item.deliveryNo);
-        if (!entry || entry.isPushing) return;
-
-        entry.isPushing = true;  // 加锁
-
-        const dto = {
-          deliveryNo: item.deliveryNo,
-          machine: item.machine,
-          operator: item.operator,
-          operationTime: item.operationTime
-        };
-
-        receive(dto).then(res => {
-          const result = markAsPushed(item.deliveryNo);
-          entry.isPushing = false;  // 请求完成解锁
-          item.isPush = 1;
-          scanSuccess();
-          status = true
-          errNum.value -= 1
-          showNotify({
-            type: 'success',
-            style: 'font-size: 30px !important;height:50px',
-            message: '推送成功!'
-          });
-        }).catch(err => {
-          entry.isPushing = false;  // 请求失败解锁
-          scanError();
-          status = true
-          showNotify({
-            type: 'danger',
-            style: 'font-size: 30px !important;height:50px',
-            message: `推单失败!${err.message}`
-          });
-        });
-      }, 500)  // 500ms防抖时间
-    });
-  }
-
-  // 执行防抖函数
-  const { debouncedFn } = debounceMap.get(item.deliveryNo);
-  debouncedFn();
-};
-
-const getUserName = (userId) => {
-  getUserNameById(userId, mac.value).then(res => {
-    if (res && res.data) {
-      saveUserId(userInfo.value.userId)
-      userInfo.value.name = res.data
-      scanSuccess()
-      showNotify({ type: 'success', style: 'font-size: 30px !important;height:50px', message: '登录成功!' });
-    }
-  })
-}
-
-const versionName = ref('')
-const _openSetting = () => {
-  closeListener()
-  setting.value.show = true
-  versionName.value = getVersionName()
-}
-
-
-// 校验mac地址是否已配置
-const _verifyMac = (done) => {
-  if (!mac.value) {
-    setting.value.show = true
-    return false
-  }
-  return true
-}
+import { openCamera, openGallery, openImageEditor } from '@/utils/android'
+import { ref } from 'vue'
 
-// 关闭设置
-const _closeSetting = () => {
-  _openScan()
+const imagePath = ref('')
+const _openCamera = () => {
+  imagePath.value = openCamera()
 }
 
-const _saveMac = () => {
-  if(!isValidMacAddress(setting.value.mac)) {
-    showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请输入正确的MAC地址!' });
-    return
-  }
-  if (!isValidPassword(setting.value.password)) {
-    showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '请输入正确的密码!' });
-    return
-  }
-  if(!saveMacAddress(setting.value.mac)) {
-    showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: 'MAC保存失败!' });
-    return
-  }
-  showNotify({ type: 'success', style: 'font-size: 30px !important;height:50px', message: 'MAC保存成功!' });
-  mac.value = setting.value.mac
-  getFrogPosition()
+const _openGallery = () => {
+  openGallery()
 }
 
-function isValidMacAddress(mac) {
-  const regex = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/;
-  return mac !== null && regex.test(mac);
-}
-function isValidPassword(password) {
-  return password === '123456';
-}
-
-// 网络状态和ip
-const ipAddress = ref(null)
-
-// 获取 IP 地址
-const fetchIP = async () => {
-  const RTCPeerConnection = window.RTCPeerConnection;
-  if (RTCPeerConnection) {
-    const pc = new RTCPeerConnection({ iceServers: [] });
-    pc.createDataChannel('');
-    pc.createOffer()
-      .then(sdp => pc.setLocalDescription(sdp))
-      .catch(console.error);
-    pc.onicecandidate = e => {
-      if (!e.candidate) return;
-      const ip = /([0-9]{1,3}(\.[0-9]{1,3}){3})/.exec(e.candidate.candidate)?.[1];
-      if (ip) ipAddress.value = ip;
-    };
-  }
-}
-
-const getErrNum = () => {
-  return getErrRecordsCount()
-}
-
-const page = ref(1)
-const size = ref(10)
-// 模拟数据加载
-const onLoad = () => {
-  if (refreshing.value) {
-    list.value = [];
-    refreshing.value = false;
-  }
-  const result = pageDelivery(page.value, size.value)
-  if (result.size < size.value) {
-    finished.value = true;
-  } else {
-    page.value += 1
-  }
-  list.value.push(...result)
-  loading.value = false;
-};
-const refreshing = ref(false);
-const onRefresh = () => {
-  // 清空列表数据
-  finished.value = false;
-
-  // 重新加载数据
-  // 将 loading 设置为 true,表示处于加载状态
-  loading.value = true;
-  page.value = 1
-  onLoad();
-};
-const isOnePush = ref(false)
-const _one_click_push = () => {
-  isOnePush.value = true
-  const result = listErrRecords()
-  if (result && result != '[]') {
-    const records = JSON.parse(result);
-    const promises = []; // 收集所有请求的Promise
-
-    records.forEach(item => {
-      // 初始化当前单据的防抖状态
-      if (!debounceMap.has(item.deliveryNo)) {
-        const debounceEntry = {
-          isPushing: false,
-          debouncedFn: debounce(() => {
-            const entry = debounceMap.get(item.deliveryNo);
-            if (!entry || entry.isPushing) return;
-
-            entry.isPushing = true;  // 加锁
-
-            const dto = {
-              deliveryNo: item.deliveryNo,
-              machine: item.machine,
-              operator: item.operator,
-              operationTime: item.operationTime
-            };
-
-            // 将请求包装成Promise并收集
-            const promise = receive(dto)
-              .then(res => {
-                const result = markAsPushed(item.deliveryNo);
-                list.value.filter(entry => entry.deliveryNo === item.deliveryNo).forEach(entry => {
-                  entry.isPush = 1;
-                })
-                errNum.value -= 1
-              })
-              .finally(() => {
-                entry.isPushing = false; // 无论成功失败都解锁
-              });
-
-            promises.push(promise); // 添加到Promise数组
-            return promise;
-          }, 500)
-        };
-        debounceMap.set(item.deliveryNo, debounceEntry);
-      }
-
-      // 立即执行防抖函数并收集Promise
-      const promise = debounceMap.get(item.deliveryNo).debouncedFn();
-      if (promise) promises.push(promise);
-    });
-
-    // 所有请求完成后重置状态
-    Promise.allSettled(promises)
-      .then(_ => {
-        scanSuccess();
-        showNotify({ type: 'success', style: 'font-size: 30px !important;height:50px', message: '数据已推送!' });
-      })
-      .catch(_ => {
-        scanError();
-        showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '存在数据推送失败!' });
-      }).finally(() => {
-      isOnePush.value = false;
-    });
-  } else {
-    showNotify({ type: 'danger', style: 'font-size: 30px !important;height:50px', message: '暂无异常数据!' });
-    isOnePush.value = false; // 没有数据时立即重置
-  }
+const _openImageEditor = () => {
+  openImageEditor(imagePath.value)
 }
 </script>
 
 <style scoped lang="sass">
-*
-  margin: 0
-  padding: 0
-  box-sizing: border-box
-
-
-body
-  font-family: "PingFang SC", "Microsoft YaHei", sans-serif
-  background: #f5f7fa
-  color: #333
-  overflow: hidden
-  height: 100vh
-
-.container
-  height: 100vh
-  display: flex
-  overflow: hidden
-  font-size: large
-  background: #fff
-
-span
-  font-size: 7px
-
-.table-container
-  display: flex
-  flex-direction: column
-  height: 100%
-  overflow: hidden
-  background: #fff
-
-.waterfall-table
-  position: relative
-  flex: 1
-  display: flex
-  flex-direction: column
-  overflow: hidden
-  height: 100%
-
-.table-header
-  font-size: 8px
-  display: flex
-  background: #f2f3f5
-  font-weight: bold
-  z-index: 0
-  box-shadow: 0 2px 4px rgba(0,0,0,0.05)
-  flex-shrink: 0  // 防止表头被压缩
-
-.table-body
-  flex: 1
-  overflow-y: auto
-  position: relative
-  padding-top: 0  // 移除之前的padding-top
-
-.table-row
-  font-size: 10px
-  height: 21px
-  display: flex
-  box-sizing: border-box
-
-.col
-  padding: 8px 4px
-  overflow: hidden
-  text-overflow: ellipsis
-  box-sizing: border-box
-
-/* 列宽设置 - 确保表头和表体使用相同的宽度 */
-.index
-  flex: 0 0 30px
-  width: 30px
-  text-align: center
-
-.time
-  flex: 0 0 75px
-  width: 75px
-
-.operator
-  flex: 0 0 55px
-  width: 55px
-
-.content
-  flex: 1
-  min-width: 0 /* 允许内容换行 */
-  white-space: normal /* 允许换行 */
-
-.status
-  flex: 0 0 40px
-  width: 40px
-
-/* 确保表体中的单元格与表头对齐 */
-:deep(.van-list)
-  .van-cell
-    padding: 0
-    width: 100%
-    box-sizing: border-box
-  .van-cell__title, .van-cell__value
-    flex: none
-
-.add
-  position: fixed
-  bottom: 10px
-  left: 10px
-  width: 20px
-  height: 20px
-  border-radius: 50%
-  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15)
-
-:deep(.custom-cell-group)
-  height: auto  // 移除固定高度
-  display: flex
-  align-items: center
-  min-height: 24px  // 确保有足够高度
-  .van-cell
-    display: flex
-    align-items: center
-    height: 100%
-  .van-cell__title
-    flex: 0 0 30px !important
-    font-size: 10px
-    line-height: 24px
-    max-width: 70px
-    min-width: 70px
-  .van-cell__value
-    flex: 1
-    line-height: 24px
-    color: red
-    font-size: 13px
-    text-align: left
-  .success-message
-    font-size: 12px
-    color: #2ed573 !important
-
-.van-notice-bar
-  background-color: #f8f9fa
-  margin: 5px 0 5px 0
-  border: 1px solid #eaeaea
-
-.van-field
-  padding: 5px 16px
-  transition: border-color 0.3s
-
-:deep(.custom-notify)
-  font-size: 100px
-
-.network-alert
-  position: fixed
-  top: 0
-  left: 0
-  right: 0
-  padding: 15px
-  text-align: center
-  font-weight: bold
-  z-index: 9999
-  animation: slideIn 0.3s ease-out
-
-
-@keyframes slideIn
-  from
-    opacity: 0
-    transform: translateY(-100%)
-  to
-    opacity: 1
-    transform: translateY(0)
-
-.network-alert.offline
-  background-color: #ff4757
-  color: white
-
-.network-alert.online
-  background-color: #2ed573
-  color: white
-  top: 0px
-
-.fade-leave-active
-  transition: opacity 0.5s ease
-
-.fade-leave-to
-  opacity: 0
-
-/* 左侧用户信息面板样式优化 */
-.user-panel
-  background-color: #f5f7fa
-  padding: 10px 10px
-  height: 100%
-  display: flex
-  flex-direction: column
-
-.user-header
-  text-align: center
-  margin-bottom: 6px
-  position: relative
-  padding-bottom: 6px
-
-.user-header h3
-  color: #3498db
-  font-weight: 500
-  font-size: 10px
-
-.user-header::after
-  content: ''
-  position: absolute
-  bottom: 0
-  left: 0
-  right: 0
-  height: 2px
-  background: linear-gradient(to right, transparent, #3498db, transparent)
-
-.info-grid
-  display: grid
-  grid-template-columns: 1fr
-  padding-bottom: 5px
-  gap: 0px
-  flex: 1
-
-.info-item
-  display: flex
-  flex-direction: column
-
-.info-label
-  font-size: 7px
-  color: #7f8c8d
-  margin-bottom: 1px
-  display: flex
-  align-items: center
-
-.info-label::before
-  content: ''
-  display: inline-block
-  width: 3px
-  height: 10px
-  background-color: #3498db
-  margin-right: 3px
-  border-radius: 2px
-
-.info-value
-  font-size: 8px
-  font-weight: 400
-  color: #1e1f1f
-  padding-left: 8px
-
-.error-section
-  padding-bottom: 25px
-
-.error-display
-  background: #fff5f5
-  padding: 3px 4px
-  border-radius: 3px
-  box-shadow: 0 2px 8px rgba(0,0,0,0.1)
-
-.error-label
-  font-size: 8px
-  color: #778181
-
-.error-count
-  font-size: 10px
-  font-weight: bold
-  color: #ff4757
-
-.retry-btn
-  width: 45px
-  height: 18px
-  font-size: 7px
-  font-weight: bold
-  border-radius: 4px
-  box-shadow: 0 4px 10px rgba(231, 76, 60, 0.3)
-  transition: all 0.3s
-  margin-top: 5px
-  margin-left: 28px
 </style>