This commit is contained in:
2026-06-02 15:28:25 +08:00
commit b271b84f70
249 changed files with 42240 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 导入模块
import user from './modules/user'
import app from './modules/app'
import sync from './modules/sync'
import print from './modules/print'
import scale from './modules/scale'
import scan from './modules/scan'
export default new Vuex.Store({
modules: {
user,
app,
sync,
print,
scale,
scan
},
strict: process.env.NODE_ENV !== 'production'
})
+114
View File
@@ -0,0 +1,114 @@
export default {
namespaced: true,
state: {
loading: {
show: false,
text: '加载中...'
},
settings: {
autoSync: true,
syncInterval: 5, // 分钟
scanContinuous: true,
scanBeep: true,
scanVibrate: true
},
systemInfo: null,
appVersion: '1.0.0'
},
mutations: {
SET_LOADING(state, { show, text }) {
state.loading.show = show
if (text) {
state.loading.text = text
}
},
SET_SETTINGS(state, settings) {
state.settings = { ...state.settings, ...settings }
},
SET_SYSTEM_INFO(state, info) {
state.systemInfo = info
}
},
actions: {
async initAppData({ commit, dispatch }) {
try {
// 初始化系统信息
await dispatch('loadSystemInfo')
// 初始化设置
await dispatch('initSettings')
} catch (error) {
console.error('初始化应用数据失败:', error)
throw error
}
},
async loadSystemInfo({ commit }) {
try {
const systemInfo = uni.getSystemInfoSync()
commit('SET_SYSTEM_INFO', systemInfo)
return systemInfo
} catch (error) {
console.error('获取系统信息失败:', error)
return null
}
},
async initSettings({ commit, state }) {
try {
// 从本地存储加载设置
const savedSettings = uni.getStorageSync('appSettings')
if (savedSettings) {
commit('SET_SETTINGS', savedSettings)
} else {
// 保存默认设置
uni.setStorageSync('appSettings', state.settings)
}
} catch (error) {
console.error('初始化设置失败:', error)
}
},
async saveSettings({ commit, state }, settings) {
try {
commit('SET_SETTINGS', settings)
uni.setStorageSync('appSettings', state.settings)
return true
} catch (error) {
console.error('保存设置失败:', error)
return false
}
},
async logError({ }, errorInfo) {
try {
const errorLog = {
...errorInfo,
timestamp: new Date().toISOString(),
deviceId: this.state.app.systemInfo?.deviceId || 'unknown'
}
const logs = uni.getStorageSync('errorLogs') || []
logs.unshift(errorLog)
// 只保留最近100条错误日志
if (logs.length > 100) {
logs.splice(100)
}
uni.setStorageSync('errorLogs', logs)
} catch (error) {
console.error('记录错误日志失败:', error)
}
}
},
getters: {
isLoading: state => state.loading.show,
loadingText: state => state.loading.text,
appSettings: state => state.settings
}
}
+167
View File
@@ -0,0 +1,167 @@
export default {
namespaced: true,
state: {
// 打印机配置对象
printerConfig: {
connected: false, // 是否已连接
deviceId: '', // 蓝牙设备ID
deviceName: '', // 蓝牙设备名称
model: '', // 打印机型号
paperWidth: 100, // 纸张宽度(mm) - 统一默认值
paperHeight: 100, // 纸张高度(mm) - 统一默认值
serviceId: '', // 蓝牙服务ID
writeCharId: '', // 蓝牙特征值ID
lastUpdated: new Date().toISOString()
}
},
mutations: {
// 设置打印机配置(合并更新)
SET_PRINTER_CONFIG(state, config) {
state.printerConfig = { ...state.printerConfig, ...config };
state.printerConfig.lastUpdated = new Date().toISOString();
},
// 清除打印机配置
CLEAR_PRINTER_CONFIG(state) {
state.printerConfig = {
connected: false,
deviceId: '',
deviceName: '',
model: '',
paperWidth: 100,
paperHeight: 100,
serviceId: '',
writeCharId: '',
lastUpdated: new Date().toISOString()
};
}
},
actions: {
// 初始化打印机配置(从本地存储加载)
async initPrinterConfig({ commit }) {
try {
const printerConfig = uni.getStorageSync('printerConfig');
if (printerConfig) {
commit('SET_PRINTER_CONFIG', printerConfig);
} else {
// 创建默认配置
const defaultConfig = {
connected: false,
deviceId: '',
deviceName: '',
model: '',
paperWidth: 100,
paperHeight: 100,
serviceId: '',
writeCharId: '',
lastUpdated: new Date().toISOString()
};
uni.setStorageSync('printerConfig', defaultConfig);
commit('SET_PRINTER_CONFIG', defaultConfig);
}
return true;
} catch (error) {
console.error('初始化打印机配置失败:', error);
return false;
}
},
// 保存打印机配置到本地存储
async savePrinterConfig({ commit, state }, config) {
try {
if (config) {
commit('SET_PRINTER_CONFIG', config);
}
uni.setStorageSync('printerConfig', state.printerConfig);
return true;
} catch (error) {
console.error('保存打印机配置失败:', error);
return false;
}
},
// 连接打印机(更新连接状态并保存)
async connectPrinter({ commit, dispatch }, device) {
try {
const config = {
connected: true,
deviceId: device.deviceId,
deviceName: device.name || device.localName,
lastUpdated: new Date().toISOString()
};
await dispatch('savePrinterConfig', config);
return true;
} catch (error) {
console.error('连接打印机失败:', error);
return false;
}
},
// 断开打印机连接
async disconnectPrinter({ commit, dispatch }) {
try {
const config = {
connected: false,
deviceId: '',
deviceName: '',
lastUpdated: new Date().toISOString()
};
await dispatch('savePrinterConfig', config);
return true;
} catch (error) {
console.error('断开打印机失败:', error);
return false;
}
},
// 清除打印机配置(重置并删除本地存储)
async clearPrinterConfig({ commit }) {
try {
commit('CLEAR_PRINTER_CONFIG');
uni.removeStorageSync('printerConfig');
return true;
} catch (error) {
console.error('清除打印机配置失败:', error);
return false;
}
},
// 更新纸张尺寸
async updatePaperSize({ dispatch }, { width, height }) {
try {
await dispatch('savePrinterConfig', {
paperWidth: width,
paperHeight: height,
lastUpdated: new Date().toISOString()
});
return true;
} catch (error) {
console.error('更新纸张尺寸失败:', error);
return false;
}
}
},
getters: {
// 连接状态
isPrinterConnected: state => state.printerConfig.connected,
// 设备信息
deviceId: state => state.printerConfig.deviceId,
deviceName: state => state.printerConfig.deviceName,
printerModel: state => state.printerConfig.model,
// 服务配置
serviceId: state => state.printerConfig.serviceId,
writeCharId: state => state.printerConfig.writeCharId,
// 纸张尺寸
paperWidth: state => state.printerConfig.paperWidth,
paperHeight: state => state.printerConfig.paperHeight,
paperSize: state => `${state.printerConfig.paperWidth}×${state.printerConfig.paperHeight}mm`,
// 完整配置
savedConfig: state => state.printerConfig,
// 配置是否为空
hasSavedConfig: state => !!state.printerConfig.deviceId
}
}
+130
View File
@@ -0,0 +1,130 @@
export default {
namespaced: true,
state: {
// 称重设备配置
scaleConfig: {
connected: false, // 是否已连接
deviceId: '', // 蓝牙设备ID
deviceName: '', // 蓝牙设备名称
model: 'A12', // 电子秤型号
// ========== 蓝牙通信配置 ==========
serviceId: '', // 蓝牙服务UUID
characteristicId: '', // 特征值UUID(用于接收重量数据,通常为notify类型)
writeCharacteristicId: '', // 可写特征值UUID(用于发送命令)
lastConfigured: '' // 最后配置时间
},
// 当前重量数据
currentWeight: null
},
mutations: {
SET_SCALE_CONFIG(state, config) {
state.scaleConfig = { ...state.scaleConfig, ...config }
},
SET_CURRENT_WEIGHT(state, weight) {
state.currentWeight = weight
},
SET_WEIGHT_VALUE(state, { value, unit, stable }) {
state.currentWeight = {
value,
unit: unit || (state.currentWeight && state.currentWeight.unit) || 'kg',
stable,
timestamp: new Date().toISOString()
}
}
},
actions: {
// 初始化称重设备配置
async initScaleConfig({ commit }) {
try {
const scaleConfig = uni.getStorageSync('scaleConfig')
if (scaleConfig) {
commit('SET_SCALE_CONFIG', scaleConfig)
} else {
uni.setStorageSync('scaleConfig', {
connected: false,
deviceId: '',
deviceName: '',
model: 'A12',
serviceId: '',
characteristicId: '',
writeCharacteristicId: '',
lastConfigured: ''
})
}
} catch (error) {
console.error('初始化称重设备配置失败:', error)
}
},
// 保存称重设备配置
async saveScaleConfig({ commit, state }, config) {
try {
commit('SET_SCALE_CONFIG', config)
uni.setStorageSync('scaleConfig', state.scaleConfig)
return true
} catch (error) {
console.error('保存称重设备配置失败:', error)
return false
}
},
// 更新当前重量
updateWeight({ commit }, weight) {
commit('SET_CURRENT_WEIGHT', weight)
},
// 更新重量值(简化版)
setWeightValue({ commit }, payload) {
commit('SET_WEIGHT_VALUE', payload)
},
// 连接称重设备
async connectScale({ commit, dispatch }, device) {
try {
commit('SET_SCALE_CONFIG', {
connected: true,
deviceId: device.deviceId,
deviceName: device.name || device.localName
})
await dispatch('saveScaleConfig')
return true
} catch (error) {
console.error('连接称重设备失败:', error)
return false
}
},
// 断开称重设备
async disconnectScale({ commit, dispatch }) {
try {
commit('SET_SCALE_CONFIG', {
connected: false,
deviceId: '',
deviceName: ''
})
await dispatch('saveScaleConfig')
return true
} catch (error) {
console.error('断开称重设备失败:', error)
return false
}
}
},
getters: {
isScaleConnected: state => state.scaleConfig.connected,
scaleModel: state => state.scaleConfig.model,
// ========== 蓝牙配置获取器 ==========
scaleServiceId: state => state.scaleConfig.serviceId,
scaleCharacteristicId: state => state.scaleConfig.characteristicId,
scaleWriteCharId: state => state.scaleConfig.writeCharacteristicId,
scaleDeviceId: state => state.scaleConfig.deviceId,
scaleDeviceName: state => state.scaleConfig.deviceName,
currentWeight: state => state.currentWeight,
// 格式化重量显示
formattedWeight: state => {
if (!state.currentWeight) return '-- kg'
const { value, unit } = state.currentWeight
return `${value && value.toFixed(2) || '0.00'} ${unit || 'kg'}`
}
}
}
+61
View File
@@ -0,0 +1,61 @@
/**
* 扫码模式配置 Store 模块
* 管理 安卓设备 / IDATA PDA / 带扫码PDA 三种模式
* 默认:uniapp(安卓设备)
*/
export default {
namespaced: true,
state: {
// 扫码模式:'uniapp' | 'idata' | 'android'
scanMode: 'uniapp'
},
mutations: {
SET_SCAN_MODE(state, mode) {
state.scanMode = mode
}
},
actions: {
/**
* 初始化扫码模式(从本地存储恢复,默认 uniapp)
*/
initScanMode({ commit }) {
try {
const saved = uni.getStorageSync('scanMode')
if (saved && ['uniapp', 'idata', 'android'].includes(saved)) {
commit('SET_SCAN_MODE', saved)
console.log('[Scan Store] 恢复扫码模式:', saved)
} else {
commit('SET_SCAN_MODE', 'uniapp')
uni.setStorageSync('scanMode', 'uniapp')
}
} catch (e) {
console.error('[Scan Store] 初始化失败:', e)
commit('SET_SCAN_MODE', 'uniapp')
}
},
/**
* 设置扫码模式并持久化
* @param {string} mode - 'uniapp' | 'idata' | 'android'
*/
setScanMode({ commit }, mode) {
if (!['uniapp', 'idata', 'android'].includes(mode)) {
console.error('[Scan Store] 无效的模式:', mode)
return
}
commit('SET_SCAN_MODE', mode)
uni.setStorageSync('scanMode', mode)
console.log('[Scan Store] 扫码模式已切换为:', mode)
}
},
getters: {
scanMode: state => state.scanMode,
isUniapp: state => state.scanMode === 'uniapp',
isIdata: state => state.scanMode === 'idata',
isAndroid: state => state.scanMode === 'android'
}
}
+243
View File
@@ -0,0 +1,243 @@
export default {
namespaced: true,
state: {
syncStatus: 'idle', // idle, syncing, success, error
lastSyncTime: null,
syncProgress: 0,
pendingSyncCount: 0,
syncLog: []
},
mutations: {
SET_SYNC_STATUS(state, status) {
state.syncStatus = status
},
SET_LAST_SYNC_TIME(state, time) {
state.lastSyncTime = time
},
SET_SYNC_PROGRESS(state, progress) {
state.syncProgress = progress
},
SET_PENDING_SYNC_COUNT(state, count) {
state.pendingSyncCount = count
},
ADD_SYNC_LOG(state, log) {
state.syncLog.unshift(log)
// 只保留最近50条日志
if (state.syncLog.length > 50) {
state.syncLog.splice(50)
}
},
CLEAR_SYNC_LOG(state) {
state.syncLog = []
}
},
actions: {
async syncData({ commit, dispatch, state }) {
if (state.syncStatus === 'syncing') {
console.log('同步已在进行中')
return
}
try {
commit('SET_SYNC_STATUS', 'syncing')
commit('SET_SYNC_PROGRESS', 0)
// 记录开始同步日志
commit('ADD_SYNC_LOG', {
type: 'start',
message: '开始数据同步',
timestamp: new Date().toISOString()
})
// 获取待同步数据
const pendingData = await dispatch('getPendingSyncData')
if (pendingData.length === 0) {
commit('SET_SYNC_STATUS', 'success')
commit('SET_SYNC_PROGRESS', 100)
commit('ADD_SYNC_LOG', {
type: 'info',
message: '没有待同步的数据',
timestamp: new Date().toISOString()
})
return
}
// 开始同步
let successCount = 0
const totalCount = pendingData.length
for (let i = 0; i < pendingData.length; i++) {
const item = pendingData[i]
try {
// 模拟同步到服务器
await dispatch('syncItemToServer', item)
// 标记为已同步
await dispatch('markItemSynced', item)
successCount++
commit('SET_SYNC_PROGRESS', Math.round((i + 1) / totalCount * 100))
commit('ADD_SYNC_LOG', {
type: 'success',
message: `成功同步: ${item.type} - ${item.data.id}`,
timestamp: new Date().toISOString()
})
} catch (error) {
commit('ADD_SYNC_LOG', {
type: 'error',
message: `同步失败: ${item.type} - ${item.data.id} - ${error.message}`,
timestamp: new Date().toISOString()
})
}
// 模拟网络延迟
await new Promise(resolve => setTimeout(resolve, 500))
}
// 更新同步状态
if (successCount === totalCount) {
commit('SET_SYNC_STATUS', 'success')
} else {
commit('SET_SYNC_STATUS', 'error')
}
// 更新最后同步时间
const now = new Date().toISOString()
commit('SET_LAST_SYNC_TIME', now)
uni.setStorageSync('lastSyncTime', now)
// 更新待同步数量
await dispatch('updatePendingSyncCount')
// 记录同步完成日志
commit('ADD_SYNC_LOG', {
type: 'complete',
message: `同步完成: ${successCount}/${totalCount} 成功`,
timestamp: new Date().toISOString()
})
} catch (error) {
console.error('同步数据失败:', error)
commit('SET_SYNC_STATUS', 'error')
commit('ADD_SYNC_LOG', {
type: 'error',
message: `同步过程出错: ${error.message}`,
timestamp: new Date().toISOString()
})
}
},
async getPendingSyncData({ }) {
try {
const pendingSync = uni.getStorageSync('pendingSync') || []
return pendingSync
} catch (error) {
console.error('获取待同步数据失败:', error)
return []
}
},
async syncItemToServer({ }, item) {
// 模拟同步到服务器
// 实际应用中应该调用真实的API
return new Promise((resolve, reject) => {
setTimeout(() => {
// 模拟95%的成功率
if (Math.random() > 0.05) {
resolve({ success: true, message: '同步成功' })
} else {
reject(new Error('网络错误'))
}
}, 1000)
})
},
async markItemSynced({ }, item) {
try {
const pendingSync = uni.getStorageSync('pendingSync') || []
const updatedSync = pendingSync.filter(syncItem =>
!(syncItem.type === item.type && syncItem.data.id === item.data.id)
)
uni.setStorageSync('pendingSync', updatedSync)
// 更新本地记录状态
const recordKey = item.type === 'inbound' ? 'inboundRecords' :
item.type === 'outbound' ? 'outboundRecords' :
item.type === 'inventory' ? 'inventoryRecords' : null
if (recordKey) {
const records = uni.getStorageSync(recordKey) || []
const updatedRecords = records.map(record => {
if (record.id === item.data.id) {
return { ...record, syncStatus: 'synced' }
}
return record
})
uni.setStorageSync(recordKey, updatedRecords)
}
} catch (error) {
console.error('标记同步成功失败:', error)
throw error
}
},
async updatePendingSyncCount({ commit }) {
try {
const pendingSync = uni.getStorageSync('pendingSync') || []
commit('SET_PENDING_SYNC_COUNT', pendingSync.length)
} catch (error) {
console.error('更新待同步数量失败:', error)
}
},
async uploadErrorLogs({ }, logs) {
// 模拟上传错误日志到服务器
console.log('上传错误日志:', logs.length, '条')
},
async startAutoSync({ dispatch, state, rootState }) {
// 启动自动同步
const syncInterval = rootState.app.settings.syncInterval || 5
setInterval(async () => {
if (state.syncStatus !== 'syncing') {
await dispatch('syncData')
}
}, syncInterval * 60 * 1000)
}
},
getters: {
syncStatusText: state => {
const statusMap = {
idle: '待同步',
syncing: '同步中',
success: '同步成功',
error: '同步失败'
}
return statusMap[state.syncStatus] || '未知状态'
},
lastSyncTimeText: state => {
if (!state.lastSyncTime) return '从未同步'
const date = new Date(state.lastSyncTime)
const now = new Date()
const diff = now - date
if (diff < 60000) {
return '刚刚'
} else if (diff < 3600000) {
return Math.floor(diff / 60000) + '分钟前'
} else if (diff < 86400000) {
return Math.floor(diff / 3600000) + '小时前'
} else {
return date.toLocaleDateString('zh-CN')
}
}
}
}
+153
View File
@@ -0,0 +1,153 @@
import { api } from '@/api/index'
// Token 刷新定时器(每 23 小时自动续期)
let refreshTimer = null
const REFRESH_INTERVAL = 23 * 60 * 60 * 1000
export default {
namespaced: true,
state: {
isLogin: false,
token: '',
deviceUuid: '',
userInfo: {
id: '',
username: '',
isSuper: false,
permissionEnterpriseIds: ''
},
// 企业信息(仅存储在内存中,不缓存本地)
enterpriseInfo: {
enterpriseName: '',
fullEnterpriseName: '',
enterpriseId: ''
}
},
mutations: {
SET_LOGIN(state, status) {
state.isLogin = status
},
SET_TOKEN(state, token) {
state.token = token
},
SET_DEVICE_UUID(state, uuid) {
state.deviceUuid = uuid
},
SET_USER_INFO(state, userInfo) {
state.userInfo = userInfo
},
SET_ENTERPRISE_INFO(state, enterpriseInfo) {
state.enterpriseInfo = { ...state.enterpriseInfo, ...enterpriseInfo }
},
CLEAR_ENTERPRISE_INFO(state) {
state.enterpriseInfo = {
enterpriseName: '',
fullEnterpriseName: '',
enterpriseId: ''
}
},
LOGOUT(state) {
state.isLogin = false
state.token = ''
state.deviceUuid = ''
state.userInfo = {
id: '',
username: '',
isSuper: false,
permissionEnterpriseIds: ''
}
// 清除企业信息
state.enterpriseInfo = {
enterpriseName: '',
fullEnterpriseName: '',
enterpriseId: ''
}
}
},
actions: {
login({ commit, dispatch }, { token, userInfo, deviceUuid }) {
commit('SET_TOKEN', token)
commit('SET_USER_INFO', userInfo)
commit('SET_DEVICE_UUID', deviceUuid || '')
commit('SET_LOGIN', true)
// 保存到本地存储
uni.setStorageSync('token', token)
uni.setStorageSync('userInfo', userInfo)
uni.setStorageSync('deviceUuid', deviceUuid || '')
// 启动 Token 自动续期定时器
dispatch('startTokenRefresh')
},
logout({ commit }) {
// 清除定时器
if (refreshTimer) {
clearInterval(refreshTimer)
refreshTimer = null
}
// 尝试通知服务端登出
api.logout().catch(() => {})
commit('LOGOUT')
// 清除本地存储
uni.removeStorageSync('token')
uni.removeStorageSync('userInfo')
uni.removeStorageSync('deviceUuid')
uni.reLaunch({ url: '/pages/login/login' })
},
startTokenRefresh({ state }) {
if (refreshTimer) {
clearInterval(refreshTimer)
}
refreshTimer = setInterval(() => {
if (state.token) {
api.refreshToken().catch(() => {})
}
}, REFRESH_INTERVAL)
},
updateUserInfo({ commit, state }, updates) {
const newUserInfo = { ...state.userInfo, ...updates }
commit('SET_USER_INFO', newUserInfo)
// 更新本地存储
uni.setStorageSync('userInfo', newUserInfo)
},
// 获取企业信息(有缓存则直接返回,否则从网络获取)
async getEnterpriseInfo({ commit, state }) {
// 如果已有企业信息,直接返回
if (state.enterpriseInfo.enterpriseName || state.enterpriseInfo.fullEnterpriseName) {
return state.enterpriseInfo
}
// 否则从网络获取
try {
const res = await api.defaultInfo()
console.log('获取企业信息', res)
if (res.code === 1000) {
const enterpriseInfo = {
enterpriseName: res.data.enterprise_name || '',
fullEnterpriseName: res.data.full_enterprise_name || '',
enterpriseId: res.data.eid || ''
}
commit('SET_ENTERPRISE_INFO', enterpriseInfo)
return enterpriseInfo
}
return null
} catch (error) {
console.error('获取企业信息失败:', error)
return null
}
}
},
getters: {
isAdmin: state => state.userInfo.isSuper,
hasPermission: state => permission => {
return state.userInfo.permissionEnterpriseIds === '*' ||
(state.userInfo.permissionEnterpriseIds || '').split(',').includes(permission)
},
enterpriseName: state => state.enterpriseInfo.fullEnterpriseName || state.enterpriseInfo.enterpriseName || '',
enterpriseInfo: state => state.enterpriseInfo
}
}