Houjie
2 天以前 51c7896fd8e45085dd5cdfff11e79a00ee0a7379
上料/下料、报工/打印机配置/产线选择 、排产工单
已修改17个文件
已删除12个文件
6963 ■■■■■ 文件已修改
api/api.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
common/router/index.js 61 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
common/router/modules/routes.js 269 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
common/service/config.service.js 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
common/util/work.js 219 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/uni-calendar/calendar.js 546 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/uni-calendar/uni-calendar-item.vue 179 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/uni-calendar/uni-calendar.vue 512 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/uni-calendar/util.js 352 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/uni-collapse/uni-collapse.vue 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/uni-popup/message.js 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/uni-popup/popup.js 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/uni-popup/uni-popup-dialog.vue 243 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/uni-popup/uni-popup-message.vue 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/uni-popup/uni-popup-share.vue 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/uni-popup/uni-popup.vue 294 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/uni-transition/uni-transition.vue 279 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manifest.json 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json 503 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages.json 465 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/home/home.vue 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/index/index.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/login/login.vue 848 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/reportRepair/reportRepair.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/spare/spare.vue 436 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/user/location.vue 749 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/user/people.vue 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
store/index.js 411 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
api/api.js
@@ -8,6 +8,10 @@
    login(params) {
        return http.post('/sys/login',params)    
    },
    getLineList(){
        return http.get('base/factory/queryUserProductionLineList')
    },
    /**
      * æ‰‹æœºå·ç ç™»å½•
      */
common/router/index.js
@@ -1,64 +1,31 @@
import modules from './modules'
import Vue from 'vue'
import Router from '@/plugin/uni-simple-router/index.js'
import {
    ACCESS_TOKEN
} from '@/common/util/constants.js'
import {
    isOAuth2AppEnv
} from '@/common/util/util.js'
import {ACCESS_TOKEN} from '@/common/util/constants.js'
Vue.use(Router)
//初始化
const router = new Router({
    encodeURI: true,
    routes: [...modules] //路由表
    encodeURI:true,
    routes: [...modules]//路由表
});
const whiteList = ['/pages/login/login', '/pages/login/loginOauth2']
const whiteList = ['/pages/login/login']
//全局路由前置守卫
router.beforeEach((to, from, next) => {
    if (to.path == '/oauth2-app/login') {
        let temp = location.href;
        location.href = temp.replace('/oauth2-app/login', '/pages/login/loginOauth2')
        return;
    }
    let token = uni.getStorageSync(ACCESS_TOKEN);
    if (token) {
        if (to.path === '/pages/login/login' || to.path === '/pages/login/loginOauth2') {
            // if (from.path === '/pages/index/index') {
            //     return;
            // } else {
                // next()
            // }
            next({
                path: '/pages/index/index'
            })
        }
        next()
    } else {
    let token=uni.getStorageSync(ACCESS_TOKEN);
    if(token){
         next()
    }else{
        if (whiteList.indexOf(to.path) !== -1) {
            // åœ¨å…ç™»å½•白名单,如果进入的页面是login页面并且当前是OAuth2app环境,就进入OAuth2登录页面
            if (to.path === '/pages/login/login' && isOAuth2AppEnv()) {
                next({
                    path: '/pages/login/loginOauth2'
                })
            } else {
                // åœ¨å…ç™»å½•白名单,直接进入
                next()
            }
        } else {
            // å¦‚果当前是在OAuth2APP环境,就跳转到OAuth2登录页面
            let path = isOAuth2AppEnv() ? '/pages/login/loginOauth2' : '/pages/login/login';
            next({
                path: path
            })
          next()
        }else{
          next({ path: '/pages/login/login'})
        }
    }
    }
})
// å…¨å±€è·¯ç”±åŽç½®å®ˆå«
router.afterEach((to, from) => {
    console.log("afterEach")
});
export default router;
})
export default router;
common/router/modules/routes.js
@@ -188,7 +188,7 @@
            title: '历史点检',
        },
    },
    {
        path: '/pages/checkList/checkListDetils/checkListDetils',
        name: 'checkListDetils',
@@ -259,7 +259,7 @@
            title: '点检-执行',
        },
    },
    {
        path: '/pages/ToDoList/ToDoListCheckSure/ToDoListCheckSure',
        name: 'ToDoListCheckSure',
@@ -295,8 +295,8 @@
            title: '选择设备',
        },
    },
    {
        path: '/pages/reportRepair/reportRepairList/reportRepairList',
        name: 'reportRepairList',
@@ -304,7 +304,7 @@
            title: '报修列表',
        },
    },
    {
        path: '/pages/annotation/annotationDetail',
        name: 'annotationDetail',
@@ -318,7 +318,266 @@
        meta: {
            title: 'helloWorld',
        },
    },
    {
        path: '/pages/eam/production/ProductionManager/ProductionManager',
        name: 'ProductionManager',
        meta: {
            title: '生产管理',
        },
    }, {
        path: '/pages/eam/production/check/check',
        name: 'check',
        meta: {
            title: '齐套检查',
        },
    }, {
        path: '/pages/eam/production/process/process',
        name: 'process',
        meta: {
            title: '工艺点检',
        },
    }, {
        path: '/pages/eam/production/sample/sample',
        name: 'process',
        meta: {
            title: '样件校验',
        },
    }, {
        path: '/pages/eam/production/feed/feed',
        name: 'process',
        meta: {
            title: '上料',
        },
    }, {
        path: '/pages/eam/production/record/record',
        name: 'record',
        meta: {
            title: '操作记录',
        },
    },
    {
        path: '/pages/eam/quality/qualityInspection/qualityInspection',
        name: 'qualityInspection',
        meta: {
            title: '质量检验',
        },
    },
    {
        path: '/pages/eam/quality/defectiveProductReview/defectiveProductReview',
        name: 'defectiveProductReview',
        meta: {
            title: '不合格品审理',
        }
    },
    {
        path: '/pages/eam/quality/checkItem/checkItem',
        name: 'checkItem',
        meta: {
            title: '检验项',
        }
    },
    {
        path: '/pages/eam/quality/productionInspection/productionInspection',
        name: 'productionInspection',
        meta: {
            title: '生产检验',
        }
    }, {
        path: '/pages/eam/quality/qualityInspection/addInspection/addInspection',
        name: 'addInspection',
        meta: {
            title: '新增-生产检验',
        }
    },
    {
        path: '/pages/eam/quality/checkItemDetail/checkItemDetail',
        name: 'checkItemDetail',
        meta: {
            title: '检验明细',
        }
    },
    {
        path: '/pages/eam/quality/qualityInspectionDetail/qualityInspectionDetail',
        name: 'qualityInspectionDetail',
        meta: {
            title: '详情',
        }
    }, {
        path: '/pages/eam/quality/inspectionDetail/inspectionDetail',
        name: 'inspectionDetail',
        meta: {
            title: '检验-明细',
        }
    }, {
        path: '/pages/eam/quality/reviewDocument/reviewDocument',
        name: 'reviewDocument',
        meta: {
            title: '审理单',
        }
    },
    {
        path: '/pages/eam/production/ToDoList/ToDoList',
        name: 'ToDoList',
        meta: {
            title: '设备点检',
        }
    }, {
        path: '/pages/eam/andon/andonCall/andonCall',
        name: 'andonCall',
        meta: {
            title: '安灯呼叫',
        }
    },
    {
        path: '/pages/eam/andon/myInitiated/myInitiated',
        name: 'myInitiated',
        meta: {
            title: '我的发起',
        }
    }, {
        path: '/pages/eam/andon/andonHandler/andonHandler',
        name: 'andonHandler',
        meta: {
            title: '安灯处置',
        }
    }, {
        path: '/pages/eam/andon/andonAction/andonAction',
        name: 'andonAction',
        meta: {
            title: '安灯填报',
        }
    },
    {
        path: '/pages/eam/andon/andonDetail/andonDetail',
        name: 'andonAction',
        meta: {
            title: '安灯详情',
        }
    },
    {
        path: '/pages/eam/production/report/report',
        name: 'report',
        meta: {
            title: '报工',
        }
    }, {
        path: '/pages/eam/andon/andonAdd/andonAdd',
        name: 'andonAdd',
        meta: {
            title: '新增-安灯工单',
        }
    }, {
        path: '/pages/lineSelect/lineSelect',
        name: 'lineSelect',
        meta: {
            title: '选择产线',
        }
    },
    {
        path: '/pages/selectUsers/selectUsers',
        name: 'selectUsers',
        meta: {
            title: '选择用户',
        }
    }, {
        path: '/pages/eam/andon/andonRespond/andonRespond',
        name: 'andonRespond',
        meta: {
            title: '安灯响应',
        }
    },
    {
        path: '/pages/print-preview/print-preview',
        name: 'print-preview',
        meta: {
            title: '移库单预览',
        }
    },
    {
        path: '/pages/finished-product-preview/finished-product-preview',
        name: 'finished-product-preview',
        meta: {
            title: '成品标签预览',
        }
    },
    {
        path: '/pages/inspection-tag-preview/inspection-tag-preview',
        name: 'inspection-tag-preview',
        meta: {
            title: '检验标签预览',
        }
    },
    {
        path: '/pages/eam/production/materialLoading/materialLoading',
        name: 'materialLoading',
        meta: {
            title: '上料',
        }
    },
    {
        path: '/pages/eam/production/partBlanking/partBlanking',
        name: 'partBlanking',
        meta: {
            title: '下料',
        }
    }
]
common/service/config.service.js
@@ -1,18 +1,20 @@
let BASE_URL = ''
if (process.env.NODE_ENV == 'development') {
// let BASE_URL = 'http://192.168.1.14/jeecg-boot'
// if (process.env.NODE_ENV == 'development') {
    
    BASE_URL = '/jeecg-boot' // å¼€å‘环境
} else {
    BASE_URL = '/jeecg-boot' // ç”Ÿäº§çŽ¯å¢ƒ
}
let staticDomainURL ='/sys/common/static';
// let staticURL ='http://125.76.225.53:8086/jeecg-boot/sys/common/static/';
let staticURL ='https://fastwoke.cn:8087/jeecg-boot/sys/common/static/';
let BASE_URL = 'http://192.168.43.223:9989/'
if (process.env.NODE_ENV == 'development') {
    console.log(BASE_URL)
    BASE_URL = uni.getStorageSync('base_url') ? uni.getStorageSync('base_url') : 'http://192.168.43.223:9989/'
} else {
    BASE_URL = uni.getStorageSync('base_url') ? uni.getStorageSync('base_url') : 'http://192.168.43.223:9989/'
}
let staticDomainURL = BASE_URL + '/sys/common/static';
const configService = {
    apiUrl: BASE_URL,
    staticDomainURL: staticDomainURL,
    staticURL:staticURL
    staticDomainURL: staticDomainURL
};
export default configService
export default configService
common/util/work.js
@@ -2,32 +2,66 @@
 * å¸¸ç”¨æœåŠ¡
 * useful server
 */
const  icon_prefix="/static/home/128/"
const icon_prefix = "/static/home/128/"
export const us = {
  data:[
    {
      title:"待办",
      icon:icon_prefix+"todo.png",
      description:"待办事项",
      useCount:1000,
      page:'ToDoList'
    },
    {
      title:"已办",
      icon:icon_prefix+"todoManger.png",
      description:"已办事项",
      useCount:1000,
      page:'TaskManagerList'
export const ps = {
    data: [{
        title: "排产工单",
        icon: icon_prefix + "todo.png",
        description: "排产工单",
        useCount: 1000,
        page: 'ProductionManager'
    },
    {
         title:"扫一扫",
         icon:icon_prefix+"icon_sacan.png",
         description:"扫码",
         useCount:10000,
          page:'spare'
       }
  ]
        title: "报工",
        icon: icon_prefix + "icon_report.png",
        description: "报工",
        useCount: 1000,
        page: 'report'
    },
    {
        title: "上料",
        icon: icon_prefix + "icon_into.png",
        description: "上料",
        useCount: 1000,
        page: 'materialLoading'
    },
    {
        title: "下料",
        icon: icon_prefix + "icon_out.png",
        description: "下料",
        useCount: 1000,
        page: 'ProductionManager'
    }]
}
export const us = {
    data: [
        {
            title: "待办",
            icon: icon_prefix + "todo.png",
            description: "待办事项",
            useCount: 1000,
            page: 'ToDoList'
        },
        {
            title: "已办",
            icon: icon_prefix + "todoManger.png",
            description: "已办事项",
            useCount: 1000,
            page: 'TaskManagerList'
        },
        {
            title: "扫一扫",
            icon: icon_prefix + "icon_sacan.png",
            description: "扫码",
            useCount: 10000,
            page: 'spare'
        }
    ]
}
@@ -35,34 +69,60 @@
 * other server å…¶ä»–服务
 */
export const os = {
  data:[
    {
      title:"待点检",
      icon:icon_prefix+"xinwen.png",
      description:"设备点检",
      useCount:10000,
      page:'checkList'
    },{
      title:"待周保",
      icon:icon_prefix+"toupiao.png",
      description:"设备周保",
      useCount:10000,
      page:'baoZhou'
    },
    {
      title:"历史点检",
      icon:icon_prefix+"icon_historicalInspection.png",
      description:"历史点检",
      useCount:10000,
      page:'historicalInspection'
    },{
      title:"历史保养",
      icon:icon_prefix+"icon_historicalMaintenance.png",
      description:"历史保养",
      useCount:10000,
      page:'historicalMaintenance'
    }
  ]
    data: [{
            title: "待点检",
            icon: icon_prefix + "xinwen.png",
            description: "设备点检",
            useCount: 10000,
            page: 'checkList'
        }, {
            title: "待周保",
            icon: icon_prefix + "toupiao.png",
            description: "设备周保",
            useCount: 10000,
            page: 'baoZhou'
        },
        {
            title: "历史点检",
            icon: icon_prefix + "icon_historicalInspection.png",
            description: "历史点检",
            useCount: 10000,
            page: 'historicalInspection'
        }, {
            title: "历史保养",
            icon: icon_prefix + "icon_historicalMaintenance.png",
            description: "历史保养",
            useCount: 10000,
            page: 'historicalMaintenance'
        },
        {
            title: "历史维修",
            icon: icon_prefix + "historicalRepair.png",
            description: "历史维修",
            useCount: 10000,
            page: 'historicalRepair'
        },
        {
            title: "故障报修",
            icon: icon_prefix + "baoxiu.png",
            description: "设备报修",
            useCount: 10000,
            page: 'reportRepair'
        }, {
            title: "待维修",
            icon: icon_prefix + "repair.png",
            description: "设备维修",
            useCount: 10000,
            page: 'maintenanceReport'
        },
        // {
        //     title: "设备台账",
        //     icon: icon_prefix + "repair.png",
        //     description: "设备台账",
        //     useCount: 10000,
        //     page: 'device'
        // }
    ]
}
@@ -71,25 +131,40 @@
 * other server å…¶ä»–服务
 */
export const ws = {
  data:[
    {
      title:"报修",
      icon:icon_prefix+"baoxiu.png",
      description:"设备报修",
      useCount:10000,
      page:'reportRepair'
    },{
      title:"待维修",
      icon:icon_prefix+"repair.png",
      description:"设备维修",
      useCount:10000,
      page:'maintenanceReport'
    },{
      title:"历史维修",
      icon:icon_prefix+"historicalRepair.png",
      description:"历史维修",
      useCount:10000,
      page:'historicalRepair'
    }
  ]
    data: [{
            title: "质量检验",
            icon: icon_prefix + "icon_quality.png",
            description: "质量检验",
            useCount: 10000,
            page: 'qualityInspection'
        },
        {
            title: "不合格品审批",
            icon: icon_prefix + "icon_wait.png",
            description: "不合格品审批",
            useCount: 10000,
            page: 'defectiveProductReview'
        }
    ]
}
/**
 * other server å®‰ç¯æœåŠ¡
 */
export const as = {
    data: [{
            title: "安灯呼叫",
            icon: icon_prefix + "historicalRepair.png",
            description: "安灯呼叫",
            useCount: 10000,
            page: 'andonCall'
        },
        {
            title: "安灯处理",
            icon: icon_prefix + "historicalRepair.png",
            description: "安灯处理",
            useCount: 10000,
            page: 'andonHandler'
        }
    ]
}
components/uni-calendar/calendar.js
ÎļþÒÑɾ³ý
components/uni-calendar/uni-calendar-item.vue
ÎļþÒÑɾ³ý
components/uni-calendar/uni-calendar.vue
ÎļþÒÑɾ³ý
components/uni-calendar/util.js
ÎļþÒÑɾ³ý
components/uni-collapse/uni-collapse.vue
ÎļþÒÑɾ³ý
components/uni-popup/message.js
ÎļþÒÑɾ³ý
components/uni-popup/popup.js
ÎļþÒÑɾ³ý
components/uni-popup/uni-popup-dialog.vue
ÎļþÒÑɾ³ý
components/uni-popup/uni-popup-message.vue
ÎļþÒÑɾ³ý
components/uni-popup/uni-popup-share.vue
ÎļþÒÑɾ³ý
components/uni-popup/uni-popup.vue
ÎļþÒÑɾ³ý
components/uni-transition/uni-transition.vue
ÎļþÒÑɾ³ý
manifest.json
@@ -13,7 +13,8 @@
        //       },
        "modules" : {
            "Maps" : {},
            "Push" : {}
            "Push" : {},
            "Bluetooth" : {}
        },
        /* æ¨¡å—配置 */
        "distribute" : {
@@ -44,7 +45,9 @@
                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
                    "<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
                    "<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
                    "<uses-permission android:name=\"android.permission.BLUETOOTH\" />",
                    "<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\" />"
                ]
            },
            "ios" : {},
@@ -79,29 +82,8 @@
        }
    },
    "h5" : {
        "title" : "设备管理",
        "domain" : "fastwoke.cn",
        "router" : {
            "mode" : "hash",
            "base" : "/h5/"
        },
        "devServer" : {
            "port" : 8086,
            "https" : false,
            "proxy" : {
                /**配置服务器路径**/
                "/jeecg-boot" : {
                    "target" : "https://192.168.4.20:8086",
                    "changeOrigin" : true,
                    "secure" : false
                }
            }
        },
        "optimization" : {
            "treeShaking" : {
                "enable" : false
            }
        }
        "title" : "Do it today",
        "domain" : "myhjdc.cn"
    }
}
/**配置服务器路径**/// ç›®æ ‡æœåС噍
package-lock.json
@@ -4,10 +4,44 @@
  "lockfileVersion": 1,
  "requires": true,
  "dependencies": {
    "@babel/runtime": {
      "version": "7.28.3",
      "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.28.3.tgz",
      "integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA=="
    },
    "@claviska/jquery-minicolors": {
      "version": "2.3.6",
      "resolved": "https://registry.npmmirror.com/@claviska/jquery-minicolors/-/jquery-minicolors-2.3.6.tgz",
      "integrity": "sha512-8Ro6D4GCrmOl41+6w4NFhEOpx8vjxwVRI69bulXsFDt49uVRKhLU5TnzEV7AmOJrylkVq+ugnYNMiGHBieeKUQ=="
    },
    "@dcloudio/uni-ui": {
      "version": "1.5.7",
      "resolved": "https://registry.npmmirror.com/@dcloudio/uni-ui/-/uni-ui-1.5.7.tgz",
      "integrity": "sha512-DugxSIrQrze1FLdUOj9a+JEQ0bHGjnJTcGUK1mN/MivKg7nuKJBRWk5Ipa9sUdoBznX6ndz5h2e7Uao6x1CdCw=="
    },
    "@hyoga/uni-socket.io": {
      "version": "3.0.4",
      "resolved": "https://registry.npmmirror.com/@hyoga/uni-socket.io/-/uni-socket.io-3.0.4.tgz",
      "integrity": "sha512-m04M/ALXpTWcKoJGPDMzJosmzuopyAXF51DFN/qxLyXnbCFeQwsWOXT/XNLl4aWoBVGwQ7IptECFFRCA6z5C8A=="
    },
    "@socket.io/component-emitter": {
      "version": "3.1.2",
      "resolved": "https://registry.npmmirror.com/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
      "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="
    },
    "@types/raf": {
      "version": "3.4.3",
      "resolved": "https://registry.npmmirror.com/@types/raf/-/raf-3.4.3.tgz",
      "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw=="
    },
    "@wtto00/html2canvas": {
      "version": "1.4.3",
      "resolved": "https://registry.npmmirror.com/@wtto00/html2canvas/-/html2canvas-1.4.3.tgz",
      "integrity": "sha512-jwsb+xL8N+gjrSNABSaFdxmWtE4c7RNFjP20lo1G7gs63Qqo1phhxVBTzxc/apDVh6LgXsU2l5bwKtXd9uz65w==",
      "requires": {
        "css-line-break": "^2.1.0",
        "text-segmentation": "^1.0.3"
      }
    },
    "@zxing/library": {
      "version": "0.21.3",
@@ -23,25 +57,486 @@
      "resolved": "https://registry.npmmirror.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz",
      "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA=="
    },
    "ansi-regex": {
      "version": "5.0.1",
      "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz",
      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
    },
    "ansi-styles": {
      "version": "4.3.0",
      "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz",
      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
      "requires": {
        "color-convert": "^2.0.1"
      }
    },
    "atob": {
      "version": "2.1.2",
      "resolved": "https://registry.npmmirror.com/atob/-/atob-2.1.2.tgz",
      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
    },
    "base64-arraybuffer": {
      "version": "1.0.2",
      "resolved": "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
      "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ=="
    },
    "btoa": {
      "version": "1.2.1",
      "resolved": "https://registry.npmmirror.com/btoa/-/btoa-1.2.1.tgz",
      "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g=="
    },
    "bwip-js": {
      "version": "4.7.0",
      "resolved": "https://registry.npmmirror.com/bwip-js/-/bwip-js-4.7.0.tgz",
      "integrity": "sha512-b7oQcgbWUl8rpcZayQ32SQrBCNteiZFuLkimKKBRlPwIHCeUN2VNeUE3HCMYShe04Evxd+ucS9uUAOsvNKjQbA=="
    },
    "camelcase": {
      "version": "5.3.1",
      "resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-5.3.1.tgz",
      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
    },
    "canvg": {
      "version": "3.0.11",
      "resolved": "https://registry.npmmirror.com/canvg/-/canvg-3.0.11.tgz",
      "integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==",
      "requires": {
        "@babel/runtime": "^7.12.5",
        "@types/raf": "^3.4.0",
        "core-js": "^3.8.3",
        "raf": "^3.4.1",
        "regenerator-runtime": "^0.13.7",
        "rgbcolor": "^1.0.1",
        "stackblur-canvas": "^2.0.0",
        "svg-pathdata": "^6.0.3"
      }
    },
    "cliui": {
      "version": "6.0.0",
      "resolved": "https://registry.npmmirror.com/cliui/-/cliui-6.0.0.tgz",
      "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
      "requires": {
        "string-width": "^4.2.0",
        "strip-ansi": "^6.0.0",
        "wrap-ansi": "^6.2.0"
      }
    },
    "color-convert": {
      "version": "2.0.1",
      "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
      "requires": {
        "color-name": "~1.1.4"
      }
    },
    "color-name": {
      "version": "1.1.4",
      "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz",
      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
    },
    "core-js": {
      "version": "3.45.1",
      "resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.45.1.tgz",
      "integrity": "sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg=="
    },
    "css-line-break": {
      "version": "2.1.0",
      "resolved": "https://registry.npmmirror.com/css-line-break/-/css-line-break-2.1.0.tgz",
      "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
      "requires": {
        "utrie": "^1.0.2"
      }
    },
    "debug": {
      "version": "4.3.7",
      "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.7.tgz",
      "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
      "requires": {
        "ms": "^2.1.3"
      }
    },
    "decamelize": {
      "version": "1.2.0",
      "resolved": "https://registry.npmmirror.com/decamelize/-/decamelize-1.2.0.tgz",
      "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="
    },
    "dijkstrajs": {
      "version": "1.0.3",
      "resolved": "https://registry.npmmirror.com/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
      "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA=="
    },
    "dompurify": {
      "version": "2.5.8",
      "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-2.5.8.tgz",
      "integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==",
      "optional": true
    },
    "emoji-regex": {
      "version": "8.0.0",
      "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz",
      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
    },
    "engine.io-client": {
      "version": "6.6.3",
      "resolved": "https://registry.npmmirror.com/engine.io-client/-/engine.io-client-6.6.3.tgz",
      "integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==",
      "requires": {
        "@socket.io/component-emitter": "~3.1.0",
        "debug": "~4.3.1",
        "engine.io-parser": "~5.2.1",
        "ws": "~8.17.1",
        "xmlhttprequest-ssl": "~2.1.1"
      }
    },
    "engine.io-parser": {
      "version": "5.2.3",
      "resolved": "https://registry.npmmirror.com/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
      "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="
    },
    "extend": {
      "version": "3.0.2",
      "resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz",
      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
    },
    "fflate": {
      "version": "0.8.2",
      "resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.8.2.tgz",
      "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="
    },
    "file-saver": {
      "version": "2.0.5",
      "resolved": "https://registry.npmmirror.com/file-saver/-/file-saver-2.0.5.tgz",
      "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
    },
    "find-up": {
      "version": "4.1.0",
      "resolved": "https://registry.npmmirror.com/find-up/-/find-up-4.1.0.tgz",
      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
      "requires": {
        "locate-path": "^5.0.0",
        "path-exists": "^4.0.0"
      }
    },
    "get-caller-file": {
      "version": "2.0.5",
      "resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz",
      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
    },
    "hiprint": {
      "version": "0.3.0",
      "resolved": "https://registry.npmmirror.com/hiprint/-/hiprint-0.3.0.tgz",
      "integrity": "sha512-Yuyw1qioGgO93Hkg13TCoIuglGB2C376Y/gPmGxjOTTbtosZrQxnjpTzy3vX+vzyF5a0/FnBXrkIBwOtDAqBZw==",
      "requires": {
        "@claviska/jquery-minicolors": "^2.3.6",
        "canvg": "^3.0.10",
        "html2canvas": "^1.4.1",
        "jquery": "^3.6.0",
        "jsbarcode": "^3.11.5",
        "jspdf": "^2.5.1",
        "nzh": "^1.0.8",
        "socket.io-client": "^4.5.1"
      }
    },
    "html2canvas": {
      "version": "1.4.1",
      "resolved": "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz",
      "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
      "requires": {
        "css-line-break": "^2.1.0",
        "text-segmentation": "^1.0.3"
      }
    },
    "html5-qrcode": {
      "version": "2.3.8",
      "resolved": "https://registry.npmmirror.com/html5-qrcode/-/html5-qrcode-2.3.8.tgz",
      "integrity": "sha512-jsr4vafJhwoLVEDW3n1KvPnCCXWaQfRng0/EEYk1vNcQGcG/htAdhJX0be8YyqMoSz7+hZvOZSTAepsabiuhiQ=="
    },
    "openai": {
      "version": "5.8.3",
      "resolved": "https://registry.npmmirror.com/openai/-/openai-5.8.3.tgz",
      "integrity": "sha512-IdotKmquCnpouTRvF9xRXVhMx6K5Sc8zkD6Usf+so+NTQ+qiJ8bLSCd7LBb8b/Rof7uYltlSxJhNp+spphKI4Q=="
    "is-fullwidth-code-point": {
      "version": "3.0.0",
      "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
    },
    "jquery": {
      "version": "3.7.1",
      "resolved": "https://registry.npmmirror.com/jquery/-/jquery-3.7.1.tgz",
      "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
    },
    "jsbarcode": {
      "version": "3.12.1",
      "resolved": "https://registry.npmmirror.com/jsbarcode/-/jsbarcode-3.12.1.tgz",
      "integrity": "sha512-QZQSqIknC2Rr/YOUyOkCBqsoiBAOTYK+7yNN3JsqfoUtJtkazxNw1dmPpxuv7VVvqW13kA3/mKiLq+s/e3o9hQ=="
    },
    "jspdf": {
      "version": "2.5.2",
      "resolved": "https://registry.npmmirror.com/jspdf/-/jspdf-2.5.2.tgz",
      "integrity": "sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==",
      "requires": {
        "@babel/runtime": "^7.23.2",
        "atob": "^2.1.2",
        "btoa": "^1.2.1",
        "canvg": "^3.0.6",
        "core-js": "^3.6.0",
        "dompurify": "^2.5.4",
        "fflate": "^0.8.1",
        "html2canvas": "^1.0.0-rc.5"
      }
    },
    "locate-path": {
      "version": "5.0.0",
      "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz",
      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
      "requires": {
        "p-locate": "^4.1.0"
      }
    },
    "lodash": {
      "version": "4.17.21",
      "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
    },
    "ms": {
      "version": "2.1.3",
      "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
    },
    "nzh": {
      "version": "1.0.14",
      "resolved": "https://registry.npmmirror.com/nzh/-/nzh-1.0.14.tgz",
      "integrity": "sha512-wKgaqCSZdrySvB4RWop5g+v6IDv2IErsT6rjq06Bg0yiT9hiHYZO12GMGx/xweGVLcO2lDjX5RqWD0S/Jy9z5Q=="
    },
    "p-limit": {
      "version": "2.3.0",
      "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-2.3.0.tgz",
      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
      "requires": {
        "p-try": "^2.0.0"
      }
    },
    "p-locate": {
      "version": "4.1.0",
      "resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-4.1.0.tgz",
      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
      "requires": {
        "p-limit": "^2.2.0"
      }
    },
    "p-try": {
      "version": "2.2.0",
      "resolved": "https://registry.npmmirror.com/p-try/-/p-try-2.2.0.tgz",
      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
    },
    "path-exists": {
      "version": "4.0.0",
      "resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz",
      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
    },
    "performance-now": {
      "version": "2.1.0",
      "resolved": "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz",
      "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
    },
    "pngjs": {
      "version": "5.0.0",
      "resolved": "https://registry.npmmirror.com/pngjs/-/pngjs-5.0.0.tgz",
      "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw=="
    },
    "qrcode": {
      "version": "1.5.4",
      "resolved": "https://registry.npmmirror.com/qrcode/-/qrcode-1.5.4.tgz",
      "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
      "requires": {
        "dijkstrajs": "^1.0.1",
        "pngjs": "^5.0.0",
        "yargs": "^15.3.1"
      }
    },
    "raf": {
      "version": "3.4.1",
      "resolved": "https://registry.npmmirror.com/raf/-/raf-3.4.1.tgz",
      "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
      "requires": {
        "performance-now": "^2.1.0"
      }
    },
    "regenerator-runtime": {
      "version": "0.13.11",
      "resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
      "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
    },
    "require-directory": {
      "version": "2.1.1",
      "resolved": "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz",
      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="
    },
    "require-main-filename": {
      "version": "2.0.0",
      "resolved": "https://registry.npmmirror.com/require-main-filename/-/require-main-filename-2.0.0.tgz",
      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
    },
    "rgbcolor": {
      "version": "1.0.1",
      "resolved": "https://registry.npmmirror.com/rgbcolor/-/rgbcolor-1.0.1.tgz",
      "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw=="
    },
    "set-blocking": {
      "version": "2.0.0",
      "resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz",
      "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
    },
    "socket.io-client": {
      "version": "4.8.1",
      "resolved": "https://registry.npmmirror.com/socket.io-client/-/socket.io-client-4.8.1.tgz",
      "integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==",
      "requires": {
        "@socket.io/component-emitter": "~3.1.0",
        "debug": "~4.3.2",
        "engine.io-client": "~6.6.1",
        "socket.io-parser": "~4.2.4"
      }
    },
    "socket.io-parser": {
      "version": "4.2.4",
      "resolved": "https://registry.npmmirror.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
      "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
      "requires": {
        "@socket.io/component-emitter": "~3.1.0",
        "debug": "~4.3.1"
      }
    },
    "stackblur-canvas": {
      "version": "2.7.0",
      "resolved": "https://registry.npmmirror.com/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
      "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ=="
    },
    "string-width": {
      "version": "4.2.3",
      "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz",
      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
      "requires": {
        "emoji-regex": "^8.0.0",
        "is-fullwidth-code-point": "^3.0.0",
        "strip-ansi": "^6.0.1"
      }
    },
    "strip-ansi": {
      "version": "6.0.1",
      "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz",
      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
      "requires": {
        "ansi-regex": "^5.0.1"
      }
    },
    "svg-pathdata": {
      "version": "6.0.3",
      "resolved": "https://registry.npmmirror.com/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
      "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw=="
    },
    "text-encoding": {
      "version": "0.7.0",
      "resolved": "https://registry.npmmirror.com/text-encoding/-/text-encoding-0.7.0.tgz",
      "integrity": "sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA=="
    },
    "text-segmentation": {
      "version": "1.0.3",
      "resolved": "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz",
      "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
      "requires": {
        "utrie": "^1.0.2"
      }
    },
    "ts-custom-error": {
      "version": "3.3.1",
      "resolved": "https://registry.npmmirror.com/ts-custom-error/-/ts-custom-error-3.3.1.tgz",
      "integrity": "sha512-5OX1tzOjxWEgsr/YEUWSuPrQ00deKLh6D7OTWcvNHm12/7QPyRh8SYpyWvA4IZv8H/+GQWQEh/kwo95Q9OVW1A=="
    },
    "utrie": {
      "version": "1.0.2",
      "resolved": "https://registry.npmmirror.com/utrie/-/utrie-1.0.2.tgz",
      "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
      "requires": {
        "base64-arraybuffer": "^1.0.2"
      }
    },
    "vue-plugin-hiprint": {
      "version": "0.0.60",
      "resolved": "https://registry.npmmirror.com/vue-plugin-hiprint/-/vue-plugin-hiprint-0.0.60.tgz",
      "integrity": "sha512-a5uOMn6Nr4qlYYaVNbQKwRZJa8UcNMTflfi6J430/NDtySJB+5ArE8I8+NLjgVV56x3/qdUBs/GWuZCX5Umv1w==",
      "requires": {
        "@claviska/jquery-minicolors": "^2.3.6",
        "@wtto00/html2canvas": "^1.4.3",
        "bwip-js": "^4.0.0",
        "canvg": "^3.0.10",
        "jquery": "^3.6.0",
        "jsbarcode": "^3.11.5",
        "jspdf": "^2.5.1",
        "lodash": "^4.17.21",
        "nzh": "^1.0.8",
        "socket.io-client": "^4.5.1"
      }
    },
    "weapp-qrcode": {
      "version": "1.0.0",
      "resolved": "https://registry.npmmirror.com/weapp-qrcode/-/weapp-qrcode-1.0.0.tgz",
      "integrity": "sha512-4sa3W0rGDVJ9QaeZpAKlAuUxVyjhDwiUqHyGK/jJMsRMXnhb4yO8qWU/pZruMo+iT5J6CraS67lDMFb1VY+RaA==",
      "requires": {
        "extend": "^3.0.2"
      }
    },
    "which-module": {
      "version": "2.0.1",
      "resolved": "https://registry.npmmirror.com/which-module/-/which-module-2.0.1.tgz",
      "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="
    },
    "wrap-ansi": {
      "version": "6.2.0",
      "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
      "requires": {
        "ansi-styles": "^4.0.0",
        "string-width": "^4.1.0",
        "strip-ansi": "^6.0.0"
      }
    },
    "ws": {
      "version": "8.17.1",
      "resolved": "https://registry.npmmirror.com/ws/-/ws-8.17.1.tgz",
      "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ=="
    },
    "xmlhttprequest-ssl": {
      "version": "2.1.2",
      "resolved": "https://registry.npmmirror.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
      "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ=="
    },
    "y18n": {
      "version": "4.0.3",
      "resolved": "https://registry.npmmirror.com/y18n/-/y18n-4.0.3.tgz",
      "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
    },
    "yargs": {
      "version": "15.4.1",
      "resolved": "https://registry.npmmirror.com/yargs/-/yargs-15.4.1.tgz",
      "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
      "requires": {
        "cliui": "^6.0.0",
        "decamelize": "^1.2.0",
        "find-up": "^4.1.0",
        "get-caller-file": "^2.0.1",
        "require-directory": "^2.1.1",
        "require-main-filename": "^2.0.0",
        "set-blocking": "^2.0.0",
        "string-width": "^4.2.0",
        "which-module": "^2.0.0",
        "y18n": "^4.0.0",
        "yargs-parser": "^18.1.2"
      }
    },
    "yargs-parser": {
      "version": "18.1.3",
      "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-18.1.3.tgz",
      "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
      "requires": {
        "camelcase": "^5.0.0",
        "decamelize": "^1.2.0"
      }
    }
  }
}
package.json
@@ -18,6 +18,13 @@
        ]
    },
    "dependencies": {
        "openai": "^5.8.3"
        "@hyoga/uni-socket.io": "^3.0.4",
        "hiprint": "^0.3.0",
        "jsbarcode": "^3.12.1",
        "openai": "^5.8.3",
        "qrcode": "^1.5.4",
        "text-encoding": "^0.7.0",
        "vue-plugin-hiprint": "0.0.60",
        "weapp-qrcode": "^1.0.0"
    }
}
pages.json
@@ -181,174 +181,349 @@
            }
        },
        {
            "path" : "pages/device/deviceDeils/deviceDeils",
            "path": "pages/device/deviceDeils/deviceDeils",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/device/deviceWebDeils/deviceWebDeils",
            "style": {
                "navigationBarTitleText": "设备详情"
            }
        },
        {
            "path": "pages/ToDoList/ToDoList",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/TaskManager/TaskManagerDeils/TaskManagerDeils",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/ToDoList/ToDoListDeils/ToDoListDeils",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/checkList/checkList",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/checkList/checkListDetils/checkListDetils",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/baoZhou/baoZhou",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/baoZhou/baoZhouDetils/baoZhouDetils",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/reportRepair/reportRepair",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/maintenanceReport/maintenanceReport",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/searEquipment/searEquipment",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/reportRepair/reportRepairList/reportRepairList",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/reportRepair/reportRepairDeils/reportRepairDeils",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/maintenanceReport/maintenanceReportDetils/maintenanceReportDetils",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/ToDoList/ToDoListDeils/ToDoCheckDetils/ToDoCheckDetils",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/ToDoList/ToDoListCheckSure/ToDoListCheckSure",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/ToDoList/ToDoSpareParts/ToDoSpareParts",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/ToDoList/ToDoBaoZhou/ToDoBaoZhou",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/ToDoList/ToDoBaoZhouSure/ToDoBaoZhouSure",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/selectEquipment/selectEquipment",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/historicalInspection/historicalInspection",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/historicalMaintenance/historicalMaintenance",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/historicalRepair/historicalRepair",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/production/ProductionManager/ProductionManager",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/quality/text/text",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/production/check/check",
            "style": {
                "navigationBarTitleText": "齐套检查"
            }
        },
        {
            "path": "pages/eam/production/process/process",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/production/sample/sample",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/production/feed/feed",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/production/record/record",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/quality/qualityInspection/qualityInspection",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/quality/defectiveProductReview/defectiveProductReview",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/quality/checkItem/checkItem",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/quality/productionInspection/productionInspection",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/quality/qualityInspection/addInspection/addInspection",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/quality/checkItemDetail/checkItemDetail",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/quality/qualityInspectionDetail/qualityInspectionDetail",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/quality/inspectionDetail/inspectionDetail",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/quality/reviewDocument/reviewDocument",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/production/ToDoList/ToDoList",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/andon/andonCall/andonCall",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/andon/myInitiated/myInitiated",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/andon/andonHandler/andonHandler",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/andon/andonAction/andonAction",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/andon/andonDetail/andonDetail",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/production/report/report",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/andon/andonAdd/andonAdd",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/lineSelect/lineSelect",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/selectUsers/selectUsers",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/eam/andon/andonRespond/andonRespond",
            "style": {
                "navigationBarTitleText": ""
            }
        },
        {
            "path": "pages/print-preview/print-preview",
            "style": {
                "navigationBarTitleText": "",
                "pageOrientation": "landscape" // æ–°å¢žæ¨ªå±é…ç½®ï¼Œlandscape è¡¨ç¤ºæ¨ªå±
            }
        },
        {
            "path" : "pages/finished-product-preview/finished-product-preview",
            "style" : 
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/device/deviceWebDeils/deviceWebDeils",
            "style" :
            {
                "navigationBarTitleText" : "设备详情"
            }
        },
        {
            "path" : "pages/ToDoList/ToDoList",
            "path" : "pages/inspection-tag-preview/inspection-tag-preview",
            "style" : 
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/TaskManager/TaskManagerDeils/TaskManagerDeils",
            "path" : "pages/eam/production/materialLoading/materialLoading",
            "style" : 
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/ToDoList/ToDoListDeils/ToDoListDeils",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/checkList/checkList",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/checkList/checkListDetils/checkListDetils",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/baoZhou/baoZhou",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/baoZhou/baoZhouDetils/baoZhouDetils",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/reportRepair/reportRepair",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/maintenanceReport/maintenanceReport",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/searEquipment/searEquipment",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/reportRepair/reportRepairList/reportRepairList",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/reportRepair/reportRepairDeils/reportRepairDeils",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/maintenanceReport/maintenanceReportDetils/maintenanceReportDetils",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/ToDoList/ToDoListDeils/ToDoCheckDetils/ToDoCheckDetils",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/ToDoList/ToDoListCheckSure/ToDoListCheckSure",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/ToDoList/ToDoSpareParts/ToDoSpareParts",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/ToDoList/ToDoBaoZhou/ToDoBaoZhou",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/ToDoList/ToDoBaoZhouSure/ToDoBaoZhouSure",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/selectEquipment/selectEquipment",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/historicalInspection/historicalInspection",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/historicalMaintenance/historicalMaintenance",
            "style" :
            {
                "navigationBarTitleText" : ""
            }
        },
        {
            "path" : "pages/historicalRepair/historicalRepair",
            "path" : "pages/eam/production/partBlanking/partBlanking",
            "style" : 
            {
                "navigationBarTitleText" : ""
            }
        }
    ],
pages/home/home.vue
@@ -11,25 +11,14 @@
                </swiper-item>
            </swiper>
            <!-- è®¾å¤‡ç»´ä¿® -->
            <!-- å·¥ä½œå° -->
            <view class="cu-bar bg-white solid-bottom" :style="[{animation: 'show 0.5s 1'}]">
                <view class="action">
                    <text class='cuIcon-title text-blue'></text>工作台
                </view>
            </view>
            <!--             <view class="cu-list grid col-4 text-sm">
                <view class="cu-item animation-slide-bottom" :style="[{animationDelay: (index + 1)*0.05 + 's'}]" v-for="(item,index) in usList" :key="index" @tap="goPage(item.page)">
                    <view class="padding text-center">
                        <image :src="item.icon" style="width:28px;height:28px;">
                            <view class="cu-tag badge margin-top-sm" style="margin-left:1.2em" v-if="getTtemDotInfo(item)">
                               <block v-if="getTtemDotInfo(item)">{{getTtemDotInfo(item)}}</block>
                            </view>
                        </image>
                        <view class="margin-top-xs">{{item.title}}</view>
                    </view>
                </view>
            </view> -->
            <view class="cu-list grid col-4 text-sm">
                <view class="cu-item animation-slide-bottom" :style="[{animationDelay: (index + 1)*0.05 + 's'}]"
                    v-for="(item, index) in usList" :key="index" @tap="goPage(item.page)">
@@ -43,10 +32,10 @@
                </view>
            </view>
            <!-- è®¾å¤‡ä¿å…» -->
            <!-- è®¾å¤‡ç®¡ç† -->
            <view class="cu-bar bg-white solid-bottom margin-top" :style="[{animation: 'show 0.6s 1'}]">
                <view class="action">
                    <text class='cuIcon-title text-yellow'></text>保养
                    <text class='cuIcon-title text-yellow'></text>设备管理
                </view>
            </view>
            <view class="cu-list grid col-4 text-sm">
@@ -62,11 +51,32 @@
                </view>
            </view>
            <!-- ç”Ÿäº§ç®¡ç† -->
            <view class="cu-bar bg-white solid-bottom" :style="[{animation: 'show 0.5s 1'}]">
                <view class="action">
                    <text class='cuIcon-title text-blue'></text>生产管理
                </view>
            </view>
            <view class="cu-list grid col-4 text-sm">
                <view class="cu-item animation-slide-bottom" :style="[{animationDelay: (index + 1)*0.05 + 's'}]"
                    v-for="(item, index) in psList" :key="index" @tap="goPage(item.page)">
                    <view class="padding text-center">
                        <image :src="item.icon" style="width:28px;height:28px;">
                            <view class="cu-tag badge margin-top-sm" style="margin-left:1.2em"
                                v-if="getTtemDotInfo(item)"></view>
                        </image>
                        <view class="margin-top-xs">{{ item.title }}</view>
                    </view>
                </view>
            </view>
            <!-- è®¾å¤‡ç»´ä¿® -->
            <!-- è´¨é‡ç®¡ç† -->
            <view class="cu-bar bg-white solid-bottom margin-top" :style="[{animation: 'show 0.6s 1'}]">
                <view class="action">
                    <text class='cuIcon-title text-blue'></text>ç»´ä¿®
                    <text class='cuIcon-title text-orange'></text>质量管理
                </view>
            </view>
            <view class="cu-list grid col-4 text-sm">
@@ -82,6 +92,30 @@
                </view>
            </view>
            <!-- å®‰ç¯ç®¡ç† -->
            <view class="cu-bar bg-white solid-bottom margin-top" :style="[{animation: 'show 0.6s 1'}]">
                <view class="action">
                    <text class='cuIcon-title text-green'></text>安灯管理
                </view>
            </view>
            <view class="cu-list grid col-4 text-sm">
                <view class="cu-item animation-slide-bottom" :style="[{animationDelay: (index + 1)*0.1 + 's'}]"
                    v-for="(item,index) in asList" :key="index" @tap="goPage(item.page)">
                    <view class="padding text-center">
                        <image :src="item.icon" style="width:28px;height:28px;">
                            <view class="cu-tag badge margin-top-sm" style="margin-left:1.2em"
                                v-if="getTtemDotInfo(item)"></view>
                        </image>
                        <view class="margin-top-xs">{{item.title}}</view>
                    </view>
                </view>
            </view>
        </scroll-view>
        <view class="cu-tabbar-height margin-top"></view>
    </view>
@@ -94,7 +128,9 @@
    import {
        us,
        os,
        ws
        ws,
        ps,
        as
    } from '@/common/util/work.js'
    import socket from '@/common/js-sdk/socket/socket.js'
    export default {
@@ -102,24 +138,15 @@
        props: {
            cur: String,
        },
        // watch: {
        //     cur: {
        //         immediate: true,
        //         handler: function(val, oldVal) {
        //             console.log('cur', val, oldVal)
        //             this.initMenu()
        //         },
        //     },
        // },
        watch: {
          cur: {
            immediate: true,
            handler: function(val, oldVal) {
              console.log('cur', val, oldVal)
              // å³ä½¿å€¼æ²¡æœ‰å˜åŒ–,也主动调用 initMenu
              this.initMenu()
            },
          },
            cur: {
                immediate: true,
                handler: function(val, oldVal) {
                    console.log('cur', val, oldVal)
                    // å³ä½¿å€¼æ²¡æœ‰å˜åŒ–,也主动调用 initMenu
                    this.initMenu()
                },
            },
        },
        data() {
            return {
@@ -147,20 +174,11 @@
                        link: ''
                    }
                ],
                middleApps: [{
                        icon: 'line2_icon1.png',
                        title: '审批',
                        'text': '个人审批'
                    },
                    {
                        icon: 'line2_icon2.png',
                        title: '审批稿',
                        'text': '审批草稿箱'
                    },
                ],
                usList: us.data,
                osList: os.data,
                wsList: ws.data,
                psList: ps.data,
                asList: as.data,
                msgCount: 0,
                toDomsgCount: 0,
                unExecRepairOrderCount: 0,
pages/index/index.vue
@@ -6,14 +6,11 @@
        <!-- <spare v-if="PageCur=='spare'" :key="commponent4Key"></spare> -->
        <view class="cu-bar tabbar bg-white shadow foot">
            <view :class="PageCur=='home'?'action text-green':'action text-gray'" @click="NavChange" data-cur="home">
                <view class='cuIcon-homefill'></view>首页
                <view class='cuIcon-homefill'></view>工作台
            </view>
            <view :class="PageCur=='device'?'action text-green':'action text-gray'" @click="NavChange" data-cur="device">
                <view class='cuIcon-apps'></view>设备
            </view>
            <!-- <view :class="PageCur=='spare'?'action text-green':'action text-gray'" @click="NavChange" data-cur="spare">
                <view class='cuIcon-scan'></view>扫一扫
            </view> -->
            <view :class="PageCur=='people'?'action text-green':'action text-gray'" @click="NavChange"
                data-cur="people">
                <view class='cuIcon-people'></view>我的
@@ -31,8 +28,6 @@
                commponent1Key: 0,
                commponent2Key: 0,
                commponent3Key: 0
            }
        },
        onLoad: function() {
pages/login/login.vue
@@ -1,343 +1,543 @@
  <template>
      <view class="zai-box">
          <scroll-view scroll-y class="page">
              <view class="text-center" :style="[{animation: 'show ' + 0.4+ 's 1'}]">
                  <image src="/static/logo-lx.png" mode='aspectFit' class="zai-logo "></image>
                  <view class="zai-title text-shadow ">设备管理 </view>
              </view>
              <view class="box padding-lr-xl login-paddingtop" :style="[{animation: 'show ' + 0.6+ 's 1'}]">
                  <block v-if="loginWay==1">
                      <view class="cu-form-group margin-top  shadow-warp" :class="[shape=='round'?'round':'']">
                          <view class="title"><text class="cuIcon-people margin-right-xs"></text>账号:</view>
                          <input placeholder="请输入账号" name="input" v-model="userName"></input>
                      </view>
                      <view class="cu-form-group margin-top shadow-warp" :class="[shape=='round'?'round':'']">
                          <view class="title"><text class="cuIcon-lock margin-right-xs"></text>密码:</view>
                          <input class="uni-input" placeholder="请输入密码" :password="!showPassword" v-model="password" />
                          <view class="action text-lg">
                              <text :class="[showPassword ? 'cuIcon-attention' : 'cuIcon-attentionforbid']"
                                  @click="changePassword"></text>
                          </view>
                      </view>
                      <view class="padding text-center margin-top">
                          <button class="cu-btn bg-blue lg margin-right shadow" :loading="loading"
                              :class="[shape=='round'?'round':'']" @tap="onLogin"><text
                                  space="emsp">{{loading ? "登录中...":" ç™»å½• "}}</text>
                          </button>
                          <!-- <button class="cu-btn line-blue lg margin-left shadow" :loading="loading" :class="[shape=='round'?'round':'']"
                            @tap="loginWay=3-loginWay">短信登录
                        </button> -->
                      </view>
                  </block>
                  <block v-else>
                      <view class="cu-form-group margin-top  shadow-warp" :class="[shape=='round'?'round':'']">
                          <view class="title"><text class="cuIcon-mobile margin-right-xs"></text>手机号:</view>
                          <input placeholder="请输入手机号" type="number" maxlength="11" v-model="phoneNo"></input>
                      </view>
                      <view class="cu-form-group margin-top shadow-warp" :class="[shape=='round'?'round':'']">
                          <view class="title"><text class="cuIcon-lock margin-right-xs"></text>验证码:</view>
                          <input class="uni-input" placeholder="请输入验证码" v-model="smsCode" />
                          <view class="action">
                              <button class="cu-btn line-blue sm" :disabled="!isSendSMSEnable" @click="onSMSSend">
                                  {{ getSendBtnText }}</button>
                          </view>
                      </view>
                      <view class="padding text-center margin-top">
                          <button class="cu-btn bg-blue lg margin-right shadow" :loading="loading"
                              :class="[shape=='round'?'round':'']" @tap="onSMSLogin"><text
                                  space="emsp">{{loading ? "登录中...":" ç™»å½• "}}</text>
                          </button>
                          <button class="cu-btn line-blue lg margin-left shadow" :loading="loading"
                              :class="[shape=='round'?'round':'']" @tap="loginWay=1">账户登录
                          </button>
                      </view>
                  </block>
<template>
    <view class="zai-box">
        <scroll-view scroll-y class="page">
            <view class="text-center" :style="[{animation: 'show ' + 0.4+ 's 1'}]">
                <image src="/static/logo-lx.png" mode='aspectFit' class="zai-logo "></image>
                <view class="zai-title text-shadow ">设备管理 </view>
            </view>
            <view class="box padding-lr-xl login-paddingtop" :style="[{animation: 'show ' + 0.6+ 's 1'}]">
                <block v-if="loginWay==1">
                    <view class="cu-form-group margin-top  shadow-warp" :class="[shape=='round'?'round':'']">
                        <view class="title"><text class="cuIcon-people margin-right-xs"></text>账号:</view>
                        <input placeholder="请输入账号" name="input" v-model="userName"></input>
                    </view>
                    <view class="cu-form-group margin-top shadow-warp" :class="[shape=='round'?'round':'']">
                        <view class="title"><text class="cuIcon-lock margin-right-xs"></text>密码:</view>
                        <input class="uni-input" placeholder="请输入密码" :password="!showPassword" v-model="password" />
                        <view class="action text-lg">
                            <text :class="[showPassword ? 'cuIcon-attention' : 'cuIcon-attentionforbid']"
                                @click="changePassword"></text>
                        </view>
                    </view>
                    <view class="padding text-center margin-top">
                        <button class="cu-btn bg-blue lg margin-right shadow" :loading="loading"
                            :class="[shape=='round'?'round':'']" @tap="onLogin"><text
                                space="emsp">{{loading ? "登录中...":" ç™»å½• "}}</text>
                        </button>
                    </view>
                </block>
                <block v-else>
                    <view class="cu-form-group margin-top  shadow-warp" :class="[shape=='round'?'round':'']">
                        <view class="title"><text class="cuIcon-mobile margin-right-xs"></text>手机号:</view>
                        <input placeholder="请输入手机号" type="number" maxlength="11" v-model="phoneNo"></input>
                    </view>
                    <view class="cu-form-group margin-top shadow-warp" :class="[shape=='round'?'round':'']">
                        <view class="title"><text class="cuIcon-lock margin-right-xs"></text>验证码:</view>
                        <input class="uni-input" placeholder="请输入验证码" v-model="smsCode" />
                        <view class="action">
                            <button class="cu-btn line-blue sm" :disabled="!isSendSMSEnable" @click="onSMSSend">
                                {{ getSendBtnText }}</button>
                        </view>
                    </view>
                    <view class="padding text-center margin-top">
                        <button class="cu-btn bg-blue lg margin-right shadow" :loading="loading"
                            :class="[shape=='round'?'round':'']" @tap="onSMSLogin"><text
                                space="emsp">{{loading ? "登录中...":" ç™»å½• "}}</text>
                        </button>
                        <button class="cu-btn line-blue lg margin-left shadow" :loading="loading"
                            :class="[shape=='round'?'round':'']" @tap="loginWay=1">账户登录
                        </button>
                    </view>
                </block>
                  <!-- #ifdef APP-PLUS -->
                  <view class="padding flex flex-direction  text-center">
                      å½“前版本:{{version}}
                  </view>
                  <!-- #endif -->
                <!-- #ifdef APP-PLUS -->
                <view class="padding flex flex-direction  text-center">
                    å½“前版本:{{version}}
                </view>
                <!-- #endif -->
              </view>
          </scroll-view>
          <!-- ç™»å½•加载弹窗 -->
          <view class="cu-load load-modal" v-if="loading">
              <!-- <view class="cuIcon-emojifill text-orange"></view> -->
              <image src="/static/logo-lx.png" mode="aspectFit" class="round"></image>
              <view class="gray-text">登录中...</view>
          </view>
      </view>
            </view>
        </scroll-view>
        <!-- ç™»å½•加载弹窗 -->
        <view class="cu-load load-modal" v-if="loading">
            <image src="/static/logo-lx.png" mode="aspectFit" class="round"></image>
            <view class="gray-text">登录中...</view>
        </view>
  </template>
        <!-- äº§çº¿é€‰æ‹©å¼¹çª— - ä»Žåº•部弹出 -->
        <view class="line-modal-mask" v-if="showLineModal" @click="closeLineModal"></view>
        <view class="line-modal" v-if="showLineModal" :class="{ 'line-modal-active': showLineModal }">
            <view class="line-modal-header">
                <view class="line-modal-title">选择产线</view>
                <text class="cuIcon-close" @click="closeLineModal"></text>
            </view>
            <view class="line-modal-content">
                <view v-if="lineLoading" class="loading-view">
                    <view class="cu-load"></view>
                    <view class="text-gray">加载产线中...</view>
                </view>
                <view v-else-if="lineList.length === 0" class="empty-view">
                    <text class="cuIcon-meh text-gray text-xl"></text>
                    <view class="text-gray">暂无可用产线</view>
                </view>
                <view class="line-item" v-for="(line, index) in lineList" :key="line.id" @click="selectLine(line)"
                    :class="{ 'line-item-selected': selectedLineId === line.id }">
                    <view class="line-name">{{ line.name }}</view>
                    <text class="cuIcon-check text-blue" v-if="selectedLineId === line.id"></text>
                </view>
            </view>
            <view class="line-modal-footer">
                <button class="cu-btn bg-blue lg" @click="confirmLineSelection" :disabled="!selectedLineId">
                    ç¡®è®¤é€‰æ‹©
                </button>
            </view>
        </view>
    </view>
</template>
  <script>
      import {
          ACCESS_TOKEN,
          USER_NAME,
          USER_INFO
      } from "@/common/util/constants"
      import {
          mapActions
      } from "vuex"
      import configService from '@/common/service/config.service.js';
<script>
    import {
        ACCESS_TOKEN,
        USER_NAME,
        USER_INFO
    } from "@/common/util/constants"
    import {
        mapActions,
        mapState,
        mapGetters
    } from "vuex" // æ–°å¢žmapGetters
    import configService from '@/common/service/config.service.js';
      export default {
          data() {
              return {
                  shape: '', //round åœ†å½¢
                  loading: false,
                  userName: '',
                  password: '',
                  phoneNo: '',
                  smsCode: '',
                  showPassword: false, //是否显示明文
                  loginWay: 1, //1: è´¦å¯†ï¼Œ2:验证码
                  smsCountDown: 0,
                  smsCountInterval: null,
                  toggleDelay: false,
                  version: '',
                  //第三方登录相关信息
                  thirdType: "",
                  thirdLoginInfo: "",
                  thirdLoginState: false,
                  bindingPhoneModal: false,
                  thirdUserUuid: '',
                  id: '',
                  url: {
                      bindingThirdPhone: '/sys/thirdLogin/bindingThirdPhone'
                  }
              };
          },
          onLoad: function(options) {
              this.id = options.id;
              // #ifdef APP-PLUS
              var that = this
              plus.runtime.getProperty(plus.runtime.appid, function(wgtinfo) {
                  that.version = wgtinfo.version
              });
              // #endif
          },
          computed: {
              isSendSMSEnable() {
                  return this.smsCountDown <= 0 && this.phoneNo.length > 4;
              },
              getSendBtnText() {
                  if (this.smsCountDown > 0) {
                      return this.smsCountDown + '秒后发送';
                  } else {
                      return '发送验证码';
                  }
              },
              canSMSLogin() {
                  return this.userName.length > 4 && this.smsCode.length > 4;
              },
              canPwdLogin() {
                  return this.userName.length > 4 && this.password.length > 4;
              },
          },
          methods: {
              ...mapActions(["mLogin", "PhoneLogin", "ThirdLogin"]),
              onLogin: function() {
                  if (!this.userName || this.userName.length == 0) {
                      this.$tip.toast('请填写用户名');
                      return;
                  }
                  if (!this.password || this.password.length == 0) {
                      this.$tip.toast('请填写密码');
                      return;
                  }
                  let loginParams = {
                      username: this.userName,
                      password: this.password
                  }
                  this.loading = true;
                  this.mLogin(loginParams).then((res) => {
                      this.loading = false;
                      if (res.data.success) {
                          // #ifdef APP-PLUS
                          this.saveClientId()
                          // #endif
                          // #ifndef APP-PLUS
                          this.$tip.success('登录成功!')
                          this.$Router.replaceAll({
                              name: 'index'
                          })
                          // if (this.id) {
                          //     uni.navigateTo({
                          //         url: `/pages/device/deviceWebDeils/deviceWebDeils?equipmentId=${this.id}`
                          //     });
    export default {
        data() {
            return {
                shape: '', //round åœ†å½¢
                loading: false,
                userName: '',
                password: '',
                phoneNo: '',
                smsCode: '',
                showPassword: false, //是否显示明文
                loginWay: 1, //1: è´¦å¯†ï¼Œ2:验证码
                smsCountDown: 0,
                smsCountInterval: null,
                toggleDelay: false,
                version: '',
                //第三方登录相关信息
                thirdType: "",
                thirdLoginInfo: "",
                thirdLoginState: false,
                bindingPhoneModal: false,
                thirdUserUuid: '',
                id: '',
                url: {
                    bindingThirdPhone: '/sys/thirdLogin/bindingThirdPhone'
                },
                // äº§çº¿é€‰æ‹©ç›¸å…³
                showLineModal: false, // äº§çº¿å¼¹çª—是否显示
                lineList: [], // äº§çº¿åˆ—表
                selectedLineId: null, // å½“前选中的产线ID
                lineLoading: false // äº§çº¿åŠ è½½çŠ¶æ€
            };
        },
        computed: {
            ...mapState(['currentLineId']),
            ...mapGetters(['currentLineName']), // æ–°å¢žï¼šèŽ·å–å½“å‰äº§çº¿åç§°ï¼ˆç”¨äºŽéªŒè¯ï¼‰
            isSendSMSEnable() {
                return this.smsCountDown <= 0 && this.phoneNo.length > 4;
            },
            getSendBtnText() {
                if (this.smsCountDown > 0) {
                    return this.smsCountDown + '秒后发送';
                } else {
                    return '发送验证码';
                }
            },
            canSMSLogin() {
                return this.userName.length > 4 && this.smsCode.length > 4;
            },
            canPwdLogin() {
                return this.userName.length > 4 && this.password.length > 4;
            },
        },
        onLoad: function(options) {
            this.id = options.id;
            // #ifdef APP-PLUS
            var that = this
            plus.runtime.getProperty(plus.runtime.appid, function(wgtinfo) {
                that.version = wgtinfo.version
            });
            // #endif
        },
        methods: {
            ...mapActions(["mLogin", "PhoneLogin", "ThirdLogin", "fetchLineList", "setCurrentLine"]),
                          // } else {
                          //     this.$tip.success('登录成功!')
                          //     this.$Router.replaceAll({
                          //         name: 'index'
                          //     })
                          // }
            onLogin: function() {
                if (!this.userName || this.userName.length == 0) {
                    this.$tip.toast('请填写用户名');
                    return;
                }
                if (!this.password || this.password.length == 0) {
                    this.$tip.toast('请填写密码');
                    return;
                }
                let loginParams = {
                    username: this.userName,
                    password: this.password
                }
                this.loading = true;
                this.mLogin(loginParams).then((res) => {
                    this.loading = false;
                    if (res.data.success) {
                        console.log('账号登录成功,准备处理产线选择');
                        // #ifdef APP-PLUS
                        this.saveClientId()
                        // #endif
                        // #ifndef APP-PLUS
                        this.handleLoginSuccess()
                        // #endif
                    } else {
                        this.$tip.alert(res.data.message);
                    }
                }).catch((err) => {
                    let msg = err.data.message || "请求出现错误,请稍后再试"
                    this.loading = false;
                    this.$tip.alert(msg);
                }).finally(() => {
                    this.loading = false;
                })
            },
            saveClientId() {
                var info = plus.push.getClientInfo();
                var cid = info.clientid;
                this.$http.get("/sys/user/saveClientId", {
                    params: {
                        clientId: cid
                    }
                }).then(res => {
                    console.log("res::saveClientId>", res)
                    this.handleLoginSuccess();
                }).catch(err => {
                    console.error('保存clientId失败:', err);
                    this.handleLoginSuccess();
                })
            },
                          // #endif
                      } else {
                          this.$tip.alert(res.data.message);
                      }
                  }).catch((err) => {
                      let msg = err.data.message || "请求出现错误,请稍后再试"
                      this.loading = false;
                      this.$tip.alert(msg);
                  }).finally(() => {
                      this.loading = false;
                  })
              },
              saveClientId() {
                  var info = plus.push.getClientInfo();
                  var cid = info.clientid;
                  this.$http.get("/sys/user/saveClientId", {
                      params: {
                          clientId: cid
                      }
                  }).then(res => {
                      console.log("res::saveClientId>", res)
                      this.$tip.success('登录成功!')
                      this.$Router.replaceAll({
                          name: 'index'
                      })
                  })
              },
              changePassword() {
                  this.showPassword = !this.showPassword;
              },
              onSMSSend() {
                  let smsParams = {};
                  smsParams.mobile = this.phoneNo;
                  smsParams.smsmode = "0";
                  let checkPhone = new RegExp(/^[1]([3-9])[0-9]{9}$/);
                  if (!smsParams.mobile || smsParams.mobile.length == 0) {
                      this.$tip.toast('请输入手机号');
                      return false
                  }
                  if (!checkPhone.test(smsParams.mobile)) {
                      this.$tip.toast('请输入正确的手机号');
                      return false
                  }
                  this.$http.post("/sys/sms", smsParams).then(res => {
                      if (res.data.success) {
                          this.smsCountDown = 60;
                          this.startSMSTimer();
                      } else {
                          this.smsCountDown = 0;
                          this.$tip.toast(res.data.message);
                      }
                  });
              },
              startSMSTimer() {
                  this.smsCountInterval = setInterval(() => {
                      this.smsCountDown--;
                      if (this.smsCountDown <= 0) {
                          clearInterval(this.smsCountInterval);
                      }
                  }, 1000);
              },
              onSMSLogin() {
                  let checkPhone = new RegExp(/^[1]([3-9])[0-9]{9}$/);
            changePassword() {
                this.showPassword = !this.showPassword;
            },
                  if (!this.phoneNo || this.phoneNo.length == 0) {
                      this.$tip.toast('请填写手机号');
                      return;
                  }
                  if (!checkPhone.test(this.phoneNo)) {
                      this.$tip.toast('请输入正确的手机号');
                      return false
                  }
                  if (!this.smsCode || this.smsCode.length == 0) {
                      this.$tip.toast('请填短信验证码');
                      return;
                  }
                  let loginParams = {
                      mobile: this.phoneNo,
                      captcha: this.smsCode
                  };
                  this.PhoneLogin(loginParams).then((res) => {
                      console.log("res====》", res)
                      if (res.data.success) {
                          this.$tip.success('登录成功!')
                          this.$Router.replaceAll({
                              name: 'index'
                          })
                      } else {
                          this.$tip.error(res.data.message);
                      }
                  }).catch((err) => {
                      let msg = ((err.response || {}).data || {}).message || err.data.message || "请求出现错误,请稍后再试"
                      this.$tip.error(msg);
                  });
              },
              loginSuccess() {
                  // ç™»é™†æˆåŠŸï¼Œé‡å®šå‘åˆ°ä¸»é¡µ
                  this.$Router.replace({
                      name: 'index'
                  })
              },
              requestFailed(err) {
                  this.$message.warning("登录失败")
              },
          },
          beforeDestroy() {
              if (this.smsCountInterval) {
                  clearInterval(this.smsCountInterval);
              }
          },
      }
  </script>
            onSMSSend() {
                let smsParams = {};
                smsParams.mobile = this.phoneNo;
                smsParams.smsmode = "0";
                let checkPhone = new RegExp(/^[1]([3-9])[0-9]{9}$/);
                if (!smsParams.mobile || smsParams.mobile.length == 0) {
                    this.$tip.toast('请输入手机号');
                    return false
                }
                if (!checkPhone.test(smsParams.mobile)) {
                    this.$tip.toast('请输入正确的手机号');
                    return false
                }
                this.$http.post("/sys/sms", smsParams).then(res => {
                    if (res.data.success) {
                        this.smsCountDown = 60;
                        this.startSMSTimer();
                    } else {
                        this.smsCountDown = 0;
                        this.$tip.toast(res.data.message);
                    }
                });
            },
  <style>
      .login-paddingtop {
          padding-top: 100upx;
      }
            startSMSTimer() {
                this.smsCountInterval = setInterval(() => {
                    this.smsCountDown--;
                    if (this.smsCountDown <= 0) {
                        clearInterval(this.smsCountInterval);
                    }
                }, 1000);
            },
      .zai-box {
          padding: 0 20upx;
          padding-top: 100upx;
          position: relative;
      }
            onSMSLogin() {
                let checkPhone = new RegExp(/^[1]([3-9])[0-9]{9}$/);
      .zai-logo {
          width: 200upx;
          height: 150px;
      }
                if (!this.phoneNo || this.phoneNo.length == 0) {
                    this.$tip.toast('请填写手机号');
                    return;
                }
                if (!checkPhone.test(this.phoneNo)) {
                    this.$tip.toast('请输入正确的手机号');
                    return false
                }
                if (!this.smsCode || this.smsCode.length == 0) {
                    this.$tip.toast('请填短信验证码');
                    return;
                }
                let loginParams = {
                    mobile: this.phoneNo,
                    captcha: this.smsCode
                };
                this.PhoneLogin(loginParams).then((res) => {
                    console.log("短信登录成功,准备处理产线选择");
                    if (res.data.success) {
                        this.handleLoginSuccess();
                    } else {
                        this.$tip.error(res.data.message);
                    }
                }).catch((err) => {
                    let msg = ((err.response || {}).data || {}).message || err.data.message || "请求出现错误,请稍后再试"
                    this.$tip.error(msg);
                });
            },
      .zai-title {
          font-size: 58upx;
          color: #000000;
          text-align: center;
      }
            // ç™»å½•成功后的处理
            handleLoginSuccess() {
                console.log('进入handleLoginSuccess方法');
                this.$tip.success('登录成功!');
      .input-placeholder,
      .zai-input {
          color: #94afce;
      }
                // æ£€æŸ¥æ˜¯å¦å·²æœ‰ä¿å­˜çš„产线(包含ID和名称)
                const savedLineId = uni.getStorageSync('currentLineId');
                const savedLineName = uni.getStorageSync('currentLineName');
                console.log('本地存储的产线ID:', savedLineId, '名称:', savedLineName);
      .zai-label {
          padding: 60upx 0;
          text-align: center;
          font-size: 30upx;
          color: #a7b6d0;
      }
                if (savedLineId && savedLineName) {
                    // å·²æœ‰å®Œæ•´çš„产线信息,直接进入首页
                    console.log('已有保存的产线,直接进入首页');
                    this.navigateToHome();
                } else {
                    // æ— ä¿å­˜çš„产线,获取产线列表并显示弹窗
                    console.log('无保存的产线,准备获取产线列表');
                    this.getLineListAndShowModal();
                }
            },
      .zai-btn {
          background: #ff65a3;
          color: #fff;
          border: 0;
          border-radius: 100upx;
          font-size: 36upx;
      }
            // èŽ·å–äº§çº¿åˆ—è¡¨å¹¶æ˜¾ç¤ºå¼¹çª—
            getLineListAndShowModal() {
                console.log('进入getLineListAndShowModal方法');
                this.lineLoading = true;
                this.lineList = [];
                this.selectedLineId = null;
      .zai-btn:after {
          border: 0;
      }
                // è°ƒç”¨Vuex action获取产线列表
                this.fetchLineList().then(lineList => {
                    console.log('获取产线列表成功:', lineList);
                    this.lineList = lineList || [];
                    this.lineLoading = false;
      /*按钮点击效果*/
      .zai-btn.button-hover {
          transform: translate(1upx, 1upx);
      }
  </style>
                    // å¦‚果有产线,默认选中第一条并显示弹窗
                    if (this.lineList.length > 0) {
                        this.selectedLineId = this.lineList[0].id;
                        this.showLineModal = true;
                        console.log('产线列表不为空,显示弹窗');
                    } else {
                        console.log('产线列表为空,不显示弹窗');
                        this.$tip.toast('未获取到产线数据,请联系管理员');
                        this.navigateToHome();
                    }
                }).catch(err => {
                    console.error('获取产线列表失败:', err);
                    this.lineLoading = false;
                    this.$tip.toast('获取产线列表失败,请重试');
                    // 3秒后重试
                    setTimeout(() => {
                        this.getLineListAndShowModal();
                    }, 3000);
                });
            },
            // é€‰æ‹©äº§çº¿
            selectLine(line) {
                console.log('选中的产线:', line.id, line.name); // æ‰“印选中的产线名称
                this.selectedLineId = line.id;
            },
            // ç¡®è®¤é€‰æ‹©äº§çº¿ï¼ˆè§¦å‘Vuex保存ID和名称)
            confirmLineSelection() {
                if (!this.selectedLineId) return;
                // è°ƒç”¨setCurrentLine,Vuex会自动同步名称
                this.setCurrentLine(this.selectedLineId).then(() => {
                    console.log('产线选择成功,ID:', this.selectedLineId, '名称:', this.currentLineName);
                    this.showLineModal = false;
                    this.navigateToHome();
                });
            },
            // å…³é—­äº§çº¿é€‰æ‹©å¼¹çª—
            closeLineModal() {
                this.showLineModal = false;
            },
            // è·³è½¬åˆ°é¦–页
            navigateToHome() {
                this.$Router.replaceAll({
                    name: 'index'
                });
            },
            loginSuccess() {
                this.$Router.replace({
                    name: 'index'
                })
            },
            requestFailed(err) {
                this.$message.warning("登录失败")
            },
        },
        beforeDestroy() {
            if (this.smsCountInterval) {
                clearInterval(this.smsCountInterval);
            }
        }
    }
</script>
<style>
    /* åŽŸæœ‰æ ·å¼ä¿æŒä¸å˜ */
    .login-paddingtop {
        padding-top: 100upx;
    }
    .zai-box {
        padding: 0 20upx;
        padding-top: 100upx;
        position: relative;
    }
    .zai-logo {
        width: 200upx;
        height: 150px;
    }
    .zai-title {
        font-size: 58upx;
        color: #000000;
        text-align: center;
    }
    .input-placeholder,
    .zai-input {
        color: #94afce;
    }
    .zai-label {
        padding: 60upx 0;
        text-align: center;
        font-size: 30upx;
        color: #a7b6d0;
    }
    .zai-btn {
        background: #ff65a3;
        color: #fff;
        border: 0;
        border-radius: 100upx;
        font-size: 36upx;
    }
    .zai-btn:after {
        border: 0;
    }
    .zai-btn.button-hover {
        transform: translate(1upx, 1upx);
    }
    /* äº§çº¿é€‰æ‹©å¼¹çª—样式 */
    .line-modal-mask {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background-color: rgba(0, 0, 0, 0.5);
        z-index: 998;
        opacity: 0;
        transition: opacity 0.3s ease;
    }
    .line-modal {
        position: fixed;
        left: 0;
        right: 0;
        bottom: -100%;
        background-color: #fff;
        border-top-left-radius: 20upx;
        border-top-right-radius: 20upx;
        z-index: 999;
        transition: bottom 0.3s ease;
        max-height: 80vh;
    }
    .line-modal-active {
        bottom: 0;
    }
    .line-modal-active+.line-modal-mask {
        opacity: 1;
    }
    .line-modal-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 20upx 30upx;
        border-bottom: 1px solid #eee;
    }
    .line-modal-title {
        font-size: 34upx;
        font-weight: bold;
    }
    .line-modal-content {
        padding: 20upx;
        overflow-y: auto;
        max-height: calc(80vh - 180upx);
    }
    .line-item {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 25upx 20upx;
        border-bottom: 1px solid #f5f5f5;
        font-size: 30upx;
    }
    .line-item-selected {
        background-color: #f0f7ff;
    }
    .line-item:last-child {
        border-bottom: none;
    }
    .line-modal-footer {
        padding: 20upx 30upx;
        border-top: 1px solid #eee;
    }
    .loading-view {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        padding: 60upx 0;
    }
    .empty-view {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        padding: 60upx 0;
    }
</style>
pages/reportRepair/reportRepair.vue
@@ -1,5 +1,5 @@
<template>
    <view v-if="authIncludes('eam:reportRepair:add')" class="container">
    <view  class="container">
        <cu-custom :bgColor="NavBarColor" :isBack="true" backRouterName="productionTask">
            <block slot="backText">返回</block>
            <block slot="content">新增-报修</block>
@@ -48,7 +48,7 @@
    </view>
    <view v-else class="container">
<!--     <view v-else class="container">
        <cu-custom :bgColor="NavBarColor" :isBack="true" backRouterName="productionTask">
            <block slot="backText">返回</block>
            <block slot="content">新增-报修</block>
@@ -57,7 +57,7 @@
        <view class="padding flex flex-direction">
            å½“前用户没有操作权限
        </view>
    </view>
    </view> -->
</template>
<script>
pages/spare/spare.vue
@@ -1,134 +1,324 @@
<template>
    <view>
        <cu-custom :bgColor="NavBarColor" :isBack="true" backRouterName="index">
            <block slot="backText">返回</block>
            <block slot="content">扫一扫</block>
        </cu-custom>
        <view class="scanCode">
            <mumu-get-qrcode :continue="true" @success='qrcodeSucess' @error="qrcodeError"
                :definition="true"></mumu-get-qrcode>
        </view>
    </view>
  <view class="container">
    <cu-custom :bgColor="NavBarColor" :isBack="true" backRouterName="index">
      <block slot="backText">返回</block>
      <block slot="content">移库单打印</block>
    </cu-custom>
    <view class="print-area">
      <button @click="previewTransferOrder" class="btn test" :loading="isLoading">
        {{ isLoading ? '生成中...' : '预览移库单' }}
      </button>
    </view>
    <view class="status">
      é¢„览状态: {{ isPreview ? '已生成预览' : '未生成' }}
    </view>
    <view class="log" v-if="logList.length > 0">
      <text class="log-title">操作日志:</text>
      <view v-for="(log, index) in logList" :key="index" class="log-item">
        {{ log }}
      </view>
    </view>
  </view>
</template>
<script>
    import mumuGetQrcode from '@/uni_modules/mumu-getQrcode/components/mumu-getQrcode/mumu-getQrcode.vue';
export default {
  name: 'TransferOrderPrinter',
  data() {
    return {
      NavBarColor: '#007AFF',
      isPreview: false,
      logList: [],
      isLoading: false,
      // ç§»åº“单数据(实际项目中可从接口获取)
      orderData: {
        productionOrderNo: '112379',
        productModel: 'G-639',
        customerName: '东方日产',
        materialNo: '120047854',
        customerModel: '4200-51354',
        productionBatch: '25159847',
        factory: '双林新火炬工厂',
        quantity: '73',
        docCode: 'XHJ.QM.QMS009E',
        qrCodeText: 'C2506080024'
      }
    };
  },
  methods: {
    // æ·»åŠ æ“ä½œæ—¥å¿—
    addLog(message) {
      const time = new Date().toLocaleTimeString();
      this.logList.unshift(`[${time}] ${message}`);
      if (this.logList.length > 20) this.logList.pop();
    },
    export default {
        components: {
            mumuGetQrcode // æ³¨å†Œ
        },
        name: 'spare',
        data() {
            return {
                NavBarColor: this.NavBarColor,
                hasNavigated: false // æ ‡è®°æ˜¯å¦å·²ç»è·³è½¬
            };
        },
    // ä½¿ç”¨åœ¨çº¿API生成二维码(无Canvas依赖)
    async generateQrCode(content) {
      try {
        this.addLog('开始生成二维码...');
        // æ–¹æ¡ˆ1: ä½¿ç”¨Base64编码内容直接生成二维码(推荐)
        const base64Content = encodeURIComponent(content);
        // è¯¥é“¾æŽ¥ä¼šæ ¹æ®å†…容生成二维码,无需后端支持
        return `https://api.qrserver.com/v1/create-qr-code/?data=${base64Content}&size=120x120`;
        // æ–¹æ¡ˆ2: å¤‡ç”¨API(若方案1不可用)
        // return `https://chart.googleapis.com/chart?chs=120x120&cht=qr&chl=${base64Content}`;
      } catch (error) {
        this.addLog(`二维码生成失败: ${error.message}`);
        throw error;
      }
    },
        methods: {
            navigateToDeviceDetails(equipmentId) {
                this.hasNavigated = true; // æ ‡è®°å·²ç»è·³è½¬
                uni.redirectTo({
                    url: `/pages/device/deviceWebDeils/deviceWebDeils?equipmentId=${encodeURIComponent(equipmentId)}`,
                    success: () => {
                        console.log('Navigated to device details');
                    },
                    fail: (err) => {
                        console.error('Navigation failed:', err);
                    }
                });
            },
            qrcodeSucess(data) { // æ‰«ç æˆåŠŸ
                setTimeout(() => {
                    let equipmentId;
                    try {
                        // å…¼å®¹æ€§å¤„理:优先使用URL和URLSearchParams,如果不可用则使用字符串解析
                        if ('URL' in window && 'URLSearchParams' in window) {
                            const url = new URL(data);
                            const params = new URLSearchParams(url.hash.slice(1).split('?')[1]);
                            equipmentId = params.get('equipmentId');
                        } else {
                            // å­—符串解析方式
                            const hashIndex = data.indexOf('#');
                            if (hashIndex !== -1) {
                                const hashPart = data.substring(hashIndex + 1);
                                const paramIndex = hashPart.indexOf('?');
                                if (paramIndex !== -1) {
                                    const paramStr = hashPart.substring(paramIndex + 1);
                                    const pairs = paramStr.split('&');
                                    for (let pair of pairs) {
                                        const [key, value] = pair.split('=');
                                        if (key === 'equipmentId') {
                                            equipmentId = value;
                                            break;
                                        }
                                    }
                                }
                            }
                        }
    // ç”Ÿæˆç§»åº“单HTML并预览
    async generateTransferHTML() {
      try {
        this.isLoading = true;
        this.addLog('开始生成移库单...');
                        if (equipmentId) {
                            // ç™»å½•成功且获取到equipmentId,跳转到设备详情页面
                            this.navigateToDeviceDetails(equipmentId);
                        } else {
                            uni.showModal({
                                title: '提示',
                                content: "二维码中未找到有效的equipmentId",
                                showCancel: false
                            });
                        }
                    } catch (error) {
                        uni.showModal({
                            title: '错误',
                            content: "解析URL出错,请检查二维码内容",
                            showCancel: false
                        });
                    }
                }, 200); // å¢žåŠ 100毫秒的延迟
            },
            qrcodeError(err) { // æ‰«ç å¤±è´¥
                uni.showModal({
                    title: '摄像头授权失败',
                    content: '摄像头授权失败,请检测当前浏览器是否有摄像头权限。',
                    success: () => {
                        uni.navigateBack({}); // è¿”回到上一页
                    }
                });
            }
        }
    };
        // ç”ŸæˆäºŒç»´ç å†…容
        const qrContent = `生产订单号:${this.orderData.productionOrderNo},产品型号:${this.orderData.productModel},客户名称:${this.orderData.customerName},物料号:${this.orderData.materialNo},客户型号:${this.orderData.customerModel},生产批号:${this.orderData.productionBatch},生产分厂:${this.orderData.factory},数量:${this.orderData.quantity}`;
        // è°ƒç”¨åœ¨çº¿API生成二维码
        const qrDataUrl = await this.generateQrCode(qrContent);
        this.addLog('二维码生成成功');
        // å¤„理logo图片(使用本地资源)
        const logoUrl = '/static/index_logo.png';
        // ç”Ÿæˆç§»åº“单HTML内容
        const htmlContent = `
          <!DOCTYPE html>
          <html lang="zh-CN">
          <head>
            <meta charset="UTF-8">
            <title>移库单</title>
            <style>
              @media print {
                @page {
                  size: A4 landscape;
                  margin: 15mm;
                }
                body {
                  -webkit-print-color-adjust: exact;
                }
              }
              body {
                margin: 0;
                padding: 0;
                font-family: "Microsoft YaHei", "SimHei", sans-serif;
              }
              .transfer-order {
                width: 800px;
                height: 550px;
                border: 2px solid #000;
                box-sizing: border-box;
                margin: 20px auto;
                padding: 15px;
              }
              .header {
                display: flex;
                align-items: center;
                justify-content: space-between;
                padding: 10px 0;
                border-bottom: 2px solid #000;
                margin-bottom: 15px;
              }
              .logo img {
                width: 180px;
                height: auto;
              }
              .doc-info {
                text-align: right;
              }
              .doc-code {
                font-size: 18px;
                font-weight: bold;
                margin-bottom: 5px;
              }
              .doc-name {
                font-size: 28px;
                font-weight: bold;
                text-align: center;
                margin: 15px 0;
              }
              .divider {
                border-top: 2px solid #000;
                width: 200px;
                margin: 0 auto 15px;
              }
              table {
                width: 100%;
                border-collapse: collapse;
                table-layout: fixed;
              }
              table, th, td {
                border: 1px solid #000;
                padding: 10px;
                font-size: 15px;
                word-wrap: break-word;
              }
              .label-container {
                display: flex;
                gap: 15px;
                flex-wrap: wrap;
                padding: 5px 0;
              }
              .status-label {
                display: inline-block;
                padding: 8px 15px;
                background-color: #f0f0f0;
                border: 1px solid #ccc;
                border-radius: 4px;
                font-size: 14px;
              }
              table tr td:first-child {
                width: 120px;
              }
              table tr td[colspan="4"] {
                width: calc(100% - 120px);
              }
              .qrcode-area {
                text-align: center;
                vertical-align: middle;
              }
              .qrcode-area img {
                width: 150px;
                height: 150px;
                display: block;
                margin: 0 auto;
              }
              .qrcode-text {
                margin-top: 10px;
                text-align: center;
                font-size: 14px;
              }
            </style>
          </head>
          <body>
            <div class="transfer-order">
              <div class="header">
                <div class="logo">
                  <img src="${logoUrl}" alt="企业logo">
                </div>
                <div class="doc-info">
                  <div class="doc-code">${this.orderData.docCode}</div>
                </div>
              </div>
              <div class="doc-name">移库单</div>
              <div class="divider"></div>
              <table>
                <tr>
                  <td>生产订单号</td>
                  <td>${this.orderData.productionOrderNo}</td>
                  <td>产品型号</td>
                  <td>${this.orderData.productModel}</td>
                  <td rowspan="4" class="qrcode-area">
                    <img src="${qrDataUrl}" alt="二维码">
                    <div class="qrcode-text">${this.orderData.qrCodeText}</div>
                  </td>
                </tr>
                <tr>
                  <td>客户名称</td>
                  <td>${this.orderData.customerName}</td>
                  <td>物料号</td>
                  <td>${this.orderData.materialNo}</td>
                </tr>
                <tr>
                  <td>客户型号</td>
                  <td>${this.orderData.customerModel}</td>
                  <td>生产批号</td>
                  <td>${this.orderData.productionBatch}</td>
                </tr>
                <tr>
                  <td>生产分厂</td>
                  <td>${this.orderData.factory}</td>
                  <td>数量</td>
                  <td>${this.orderData.quantity}</td>
                </tr>
                <tr>
                  <td>检验状态</td>
                  <td colspan="4">
                    <div class="label-container">
                      <span class="status-label">合格</span>
                      <span class="status-label">已检验</span>
                    </div>
                  </td>
                </tr>
              </table>
            </div>
          </body>
          </html>
        `;
        // ç”ŸæˆBlob链接并跳转预览
        const blob = new Blob([htmlContent], { type: 'text/html' });
        const previewUrl = URL.createObjectURL(blob);
        uni.navigateTo({
          url: `/pages/print-preview/print-preview?previewUrl=${encodeURIComponent(previewUrl)}`,
          success: () => {
            this.isPreview = true;
            this.addLog('移库单预览生成成功');
          },
          fail: (err) => {
            this.addLog(`跳转预览失败: ${err.errMsg}`);
          }
        });
      } catch (error) {
        this.addLog(`生成失败: ${error.message}`);
        uni.showToast({ title: '生成失败', icon: 'none' });
      } finally {
        this.isLoading = false;
      }
    },
    // è§¦å‘预览
    previewTransferOrder() {
      if (this.isLoading) return;
      this.generateTransferHTML();
    }
  }
};
</script>
<style>
    .scanCode {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 99;
        height: 100%;
        width: 100%;
        background-color: rgba(0, 0, 0, 0.7);
    }
    .reader-box {
        position: fixed;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        background-color: rgba(0, 0, 0, 0.5);
    }
    .reader {
        width: 540rpx;
        height: 540rpx;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }
<style scoped>
.print-area {
  padding: 20rpx;
}
.btn {
  width: 100%;
  padding: 20rpx;
  margin-bottom: 15rpx;
  border-radius: 8rpx;
  color: #fff;
  font-size: 28rpx;
  background-color: #FF9500;
}
.status {
  padding: 20rpx;
  font-size: 28rpx;
  color: #666;
}
.log {
  margin: 10rpx;
  padding: 20rpx;
  background-color: #f5f5f5;
  border-radius: 10rpx;
}
.log-title {
  font-weight: bold;
  display: block;
  margin-bottom: 10rpx;
  color: #333;
}
.log-item {
  font-size: 26rpx;
  color: #666;
  margin-bottom: 5rpx;
  word-break: break-all;
}
</style>
pages/user/location.vue
@@ -1,117 +1,656 @@
<template>
    <view>
        <cu-custom :bgColor="NavBarColor" :isBack="true">
    <view class="container">
        <cu-custom :bgColor="NavBarColor" :isBack="true" backRouterName="index">
            <block slot="backText">返回</block>
            <block slot="content">定位</block>
            <block slot="content">网络打印机配置</block>
        </cu-custom>
        <map
        style="width: 100%; height:500px;"
        :latitude="latitude"
        :longitude="longitude"
        :markers="marker"
        :scale="scale"
        >
        </map>
    </view>
        <!-- æ‰“印机设置区域 -->
        <view class="setting-area">
            <view class="input-item">
                <text>打印机IP:</text>
                <uni-data-select v-model="printerIP" :localdata="printerList" @change="changePrinterList"
                    placeholder="请选择" />
                <!-- <uni-easyinput v-model="printerIP" placeholder="例如: 192.168.1.100" /> -->
            </view>
            <view class="input-item">
                <text>端口号:</text>
                <uni-easyinput v-model="printerPort" type="number" placeholder="默认: 9100" value="9100" />
            </view>
            <view class="input-item">
                <text>打印机型号:</text>
                <uni-data-select v-model="printerModel" :localdata="printerModels" placeholder="选择打印机型号" />
            </view>
            <!-- å¹³å°é™åˆ¶æç¤º -->
            <view class="platform-tip" v-if="isMini || isH5">
                âš ï¸ å°ç¨‹åº/H5 ä¸æ”¯æŒç›´æŽ¥TCP连接,需通过后端中转
            </view>
            <button @click="connectPrinter" :disabled="isConnected || (isMini || isH5)" class="btn primary">
                è¿žæŽ¥æ‰“印机(仅APP支持)
            </button>
            <button @click="connectViaBackend" :disabled="isConnected" class="btn primary-outline"
                v-if="isMini || isH5">
                é€šè¿‡åŽç«¯è¿žæŽ¥æ‰“印机
            </button>
            <button @click="disconnectPrinter" :disabled="!isConnected" class="btn danger">
                æ–­å¼€è¿žæŽ¥
            </button>
            <button @click="testPrint" :disabled="!isConnected" class="btn test">
                æµ‹è¯•打印(ZPL指令)
            </button>
        </view>
        <!-- æ‰“印内容区域 -->
        <view class="print-area" v-if="isConnected">
            <text class="print-title">选择打印模板:</text>
            <button @click="printStockLabel" class="btn print">打印成品入库标签</button>
            <button @click="printTransferOrder" class="btn print">打印移库单</button>
            <button @click="printInspectionForm(1)" class="btn print">打印检验单A</button>
            <button @click="printInspectionForm(2)" class="btn print">打印检验单B</button>
        </view>
        <!-- çŠ¶æ€æ˜¾ç¤º -->
        <view class="status">
            è¿žæŽ¥çŠ¶æ€: {{ isConnected ? '已连接(TCP)' : '未连接' }}
        </view>
        <view class="log" v-if="logList.length > 0">
            <text class="log-title">操作日志:</text>
            <view v-for="(log, index) in logList" :key="index" class="log-item">
                {{ log }}
            </view>
        </view>
    </view>
</template>
<script>
    // å¼•入设备信息判断平台(APP/小程序/H5)
    import {
        getSystemInfo,
        isApp,
        isMini,
        isH5
    } from 'common/util/system.js';
    import PrinterCommands from 'common/util/printer-commands.js';
    export default {
        data() {
            return {
                NavBarColor:this.NavBarColor,
                id:0, // ä½¿ç”¨ marker点击事件 éœ€è¦å¡«å†™id
                title: 'map',
              ã€€latitude: 40.009704,  //纬度
        ã€€ã€€    longitude: 116.374999,  //经度
          ã€€ã€€ã€€marker: [{
               ã€€ã€€id:0,
               ã€€ã€€latitude: 40.009704,//纬度
               ã€€ã€€longitude: 116.374999,//经度
               ã€€ã€€iconPath: '/static/location.png',    //显示的图标
               ã€€ã€€rotate:0,   // æ—‹è½¬åº¦æ•°
               ã€€ã€€width:20,   //宽
               ã€€ã€€height:20,   //高
              ã€€ã€€ title:'你在哪了',//标注点名
              ã€€ã€€ alpha:0.5,   //透明度
              ã€€ã€€ /* label:{//为标记点旁边增加标签   //因背景颜色H5不支持
                  ã€€ã€€ content:'北京国炬公司',//文本
                ã€€ã€€ã€€ color:'red',//文本颜色
                    ã€€ fontSize:24,//文字大小
                       x:5,//label的坐标,原点是 marker å¯¹åº”的经纬度
                       y:1,//label的坐标,原点是 marker å¯¹åº”的经纬度
                       borderWidth:12,//边框宽度
                       borderColor:'pink',//边框颜色
                    ã€€ borderRadius:20,//边框圆角
                    ã€€ bgColor:'black',//背景色
                    ã€€ padding:5,//文本边缘留白
                       textAlign:'right'//文本对齐方式。
               }, */
               callout:{//自定义标记点上方的气泡窗口 ç‚¹å‡»æœ‰æ•ˆ
               ã€€ã€€content:'北京国炬公司',//文本
               ã€€ã€€color:'#ffffff',//文字颜色
               ã€€ã€€fontSize:14,//文本大小
               ã€€ã€€borderRadius:2,//边框圆角
              ã€€ã€€ bgColor:'#00c16f',//背景颜色
               ã€€ã€€display:'ALWAYS'//常显
               }
               // anchor:{//经纬度在标注图标的锚点,默认底边中点
               //     x:0,    åŽŸç‚¹ä¸ºç»™å‡ºçš„ç»çº¬åº¦
               //     y:0,
               // }
           }],
           scale:16,//地图缩放程度
       ã€€ ã€€controls:[{//在地图上显示控件,控件不随着地图移动
          ã€€ã€€id:1,//控件id
          ã€€ã€€iconPath:'/static/login3.png',//显示的图标
              clickable:true,
          ã€€ã€€position:{//控件在地图的位置
             ã€€ã€€left:15,
             ã€€ã€€top:15,
             ã€€ã€€width:50,
             ã€€ã€€height:50
         ã€€ã€€  },
       ã€€ã€€}],
       ã€€ ã€€circles:[{//在地图上显示圆
          ã€€ã€€latitude: 40.009704,
          ã€€ã€€longitude: 116.374999,
          ã€€ã€€radius:50,//半径
              fillColor:"#ffffffAA",//填充颜色
          ã€€ã€€color:"#55aaffAA",//描边的颜色
         ã€€ã€€ strokeWidth:1//描边的宽度
          }],
       ã€€/* ã€€polyline:[{//指定一系列坐标点,从数组第一项连线至最后一项
       ã€€ã€€ã€€ã€€points:[
              ã€€ã€€{latitude: 40.009153,longitude: 116.374935},
             ã€€ã€€ {latitude: 40.009704,longitude: 116.374999},
       ã€€ã€€ã€€ã€€],
       ã€€ã€€ã€€ã€€color:"#0000AA",//线的颜色
       ã€€ã€€ã€€ã€€width:2,//线的宽度
       ã€€ã€€ã€€ã€€dottedLine:true,//是否虚线
       ã€€ã€€ã€€ã€€arrowLine:true,    //带箭头的线 å¼€å‘者工具暂不支持该属性
       ã€€ã€€}], */
         }
        },
        onLoad() {
            this.getLocation()
        name: 'NetworkPrinter',
        data() {
            return {
                printerList: [],
                NavBarColor: this.NavBarColor,
                printerIP: '', // æ–‘马打印机IP(需替换为实际值)
                printerPort: '9100', // æ–‘马默认TCP端口
                printerModel: 'zebra', // é»˜è®¤ä¸ºæ–‘马系列
                printerModels: [{
                        value: 'epson',
                        text: '爱普生(EPSON)系列'
                    },
                    {
                        value: 'zebra',
                        text: '斑马(ZEBRA)系列' // é€‰ä¸­æ–‘马
                    },
                    {
                        value: 'citizen',
                        text: '西铁城(CITIZEN)系列'
                    },
                    {
                        value: 'generic',
                        text: '通用ESC/POS兼容'
                    }
                ],
                isConnected: false,
                socketTask: null, // åŽŸç”ŸTCP Socket实例(替换Socket.io)
                logList: [],
                isMini: false, // æ˜¯å¦ä¸ºå°ç¨‹åº
                isH5: false, // æ˜¯å¦ä¸ºH5
                // åŽç«¯ä¸­è½¬æŽ¥å£åœ°å€ï¼ˆå°ç¨‹åº/H5使用)
                url: {
                    list: 'base/printerConfig/queryUserPrinterConfigList'
                },
                backendPrintUrl: '/api/printer/print'
            };
        },
        methods: {
            getLocation(){
                uni.getLocation({
                    type: 'gcj02',
                    success: function (res) {
                        console.log('当前位置的经度:' + res.longitude);
                        console.log('当前位置的纬度:' + res.latitude);
                    },
                    fail: function (res) {
                         console.log('当前位置的经度');
                    }
        onLoad() {
            // åˆå§‹åŒ–:判断当前平台
            this.initPlatform();
            // åŠ è½½ç¼“å­˜é…ç½®
            this.loadPrinterConfig();
        },
        onUnload() {
            // é¡µé¢é”€æ¯æ—¶æ–­å¼€è¿žæŽ¥
            this.disconnectPrinter();
            // ä¿å­˜é…ç½®
            this.savePrinterConfig();
        },
        created() {
            this.getPrinterList()
        },
        methods: {
            changePrinterList(e) {
                this.printerIP = e;
                console.log(this.printerIP)
            },
            getPrinterList() {
                this.$http.get(this.url.list, {
                    params: {},
                }).then(res => {
                    //设置列表数据
                    if (res.data.success) {
                        this.printerList = res.data.result
                    } else {
                        uni.showToast({
                            icon: "error",
                            title: res.data.message,
                            duration: 2000
                        });
                    }
                }).catch(() => {
                    this.$tip.error("联网失败")
                })
            },
            // åˆå§‹åŒ–平台(判断APP/小程序/H5)
            initPlatform() {
                // ç›´æŽ¥è°ƒç”¨å¯¼å…¥çš„命名方法,不会报错
                const systemInfo = getSystemInfo(); // æ­£ç¡®ï¼šè°ƒç”¨å‘½åå¯¼å‡ºçš„ getSystemInfo å‡½æ•°
                this.isApp = isApp(); // æ­£ç¡®ï¼šè°ƒç”¨å‘½åå¯¼å‡ºçš„ isApp å‡½æ•°
                this.isMini = isMini(); // æ­£ç¡®ï¼šè°ƒç”¨å‘½åå¯¼å‡ºçš„ isMini å‡½æ•°
                this.isH5 = isH5(); // æ­£ç¡®ï¼šè°ƒç”¨å‘½åå¯¼å‡ºçš„ isH5 å‡½æ•°
                this.isMini = systemInfo.platform === 'mp-weixin' || systemInfo.platform === 'mp-alipay';
                this.isH5 = systemInfo.platform === 'h5';
                if (this.isMini || this.isH5) {
                    this.addLog(`当前平台:${this.isMini ? '小程序' : 'H5'},需通过后端中转`);
                }
            },
            // åŠ è½½ä¿å­˜çš„æ‰“å°æœºé…ç½®
            loadPrinterConfig() {
                const config = uni.getStorageSync('printerConfig');
                if (config) {
                    this.printerIP = config.ip || this.printerIP;
                    this.printerPort = config.port || this.printerPort;
                    this.printerModel = config.model || this.printerModel;
                }
            },
            // ä¿å­˜æ‰“印机配置
            savePrinterConfig() {
                uni.setStorageSync('printerConfig', {
                    ip: this.printerIP,
                    port: this.printerPort,
                    model: this.printerModel
                });
            },
            // æ·»åŠ æ—¥å¿—
            addLog(message) {
                const time = new Date().toLocaleTimeString();
                this.logList.unshift(`[${time}] ${message}`);
                if (this.logList.length > 20) this.logList.pop();
            },
            // 1. APP端:直接TCP连接斑马打印机(核心修改)
            connectPrinter() {
                if (!this.printerIP || !this.printerPort) {
                    uni.showToast({
                        title: '请输入IP和端口',
                        icon: 'none'
                    });
                    return;
                }
                // å…ˆå…³é—­å·²æœ‰è¿žæŽ¥
                if (this.socketTask) this.disconnectPrinter();
                this.addLog(`正在TCP连接:${this.printerIP}:${this.printerPort}`);
                // åŽŸç”ŸTCP Socket连接(type: 'tcp' å¿…须指定)
                this.socketTask = uni.createSocket({
                    url: `tcp://${this.printerIP}:${this.printerPort}`,
                    type: 'tcp', // æ˜Žç¡®æŒ‡å®šä¸ºTCP连接(斑马打印机仅支持TCP)
                    success: () => {
                        this.addLog('Socket创建成功,等待连接...');
                        // ç›‘听连接成功
                        this.socketTask.onOpen(() => {
                            this.isConnected = true;
                            this.addLog('斑马打印机连接成功(TCP)');
                            this.savePrinterConfig();
                            uni.showToast({
                                title: '连接成功',
                                icon: 'success'
                            });
                        });
                        // ç›‘听连接错误
                        this.socketTask.onError((err) => {
                            this.isConnected = false;
                            this.addLog(`连接失败:${err.errMsg || '端口被占用或打印机离线'}`);
                            uni.showToast({
                                title: '连接失败,检查IP/端口',
                                icon: 'none'
                            });
                        });
                        // ç›‘听连接断开
                        this.socketTask.onClose((res) => {
                            this.isConnected = false;
                            this.addLog(`连接断开:${res.reason || '未知原因'}`);
                            // è¢«åŠ¨æ–­å¼€æ—¶å°è¯•é‡è¿žï¼ˆå¯é€‰ï¼‰
                            if (res.code !== 1000) {
                                setTimeout(() => this.connectPrinter(), 3000);
                            }
                        });
                    },
                    fail: (err) => {
                        this.addLog(`创建Socket失败:${err.errMsg}`);
                        uni.showToast({
                            title: '创建连接失败',
                            icon: 'none'
                        });
                    }
                });
            },
            // 2. å°ç¨‹åº/H5:通过后端中转连接(新增)
            connectViaBackend() {
                // åŽç«¯ä¸­è½¬æ— éœ€å‰ç«¯å»ºç«‹TCP,仅需保存配置并验证后端连通性
                if (!this.printerIP || !this.printerPort) {
                    uni.showToast({
                        title: '请输入IP和端口',
                        icon: 'none'
                    });
                    return;
                }
                this.addLog(`通过后端验证打印机:${this.printerIP}:${this.printerPort}`);
                // è°ƒç”¨åŽç«¯æŽ¥å£éªŒè¯æ‰“印机状态
                uni.request({
                    url: '/api/printer/checkStatus',
                    method: 'POST',
                    data: {
                        ip: this.printerIP,
                        port: this.printerPort
                    },
                    success: (res) => {
                        if (res.data.success) {
                            this.isConnected = true; // æ ‡è®°ä¸ºâ€œåŽç«¯å·²è¿žæŽ¥â€
                            this.addLog('后端连接打印机成功');
                            this.savePrinterConfig();
                            uni.showToast({
                                title: '后端连接成功',
                                icon: 'success'
                            });
                        } else {
                            this.addLog(`后端连接失败:${res.data.message}`);
                            uni.showToast({
                                title: res.data.message,
                                icon: 'none'
                            });
                        }
                    },
                    fail: (err) => {
                        this.addLog(`后端接口异常:${err.errMsg}`);
                        uni.showToast({
                            title: '后端接口不可用',
                            icon: 'none'
                        });
                    }
                });
            },
            // æ–­å¼€è¿žæŽ¥
            disconnectPrinter() {
                if (this.socketTask) {
                    this.socketTask.close({
                        success: () => {
                            this.isConnected = false;
                            this.socketTask = null;
                            this.addLog('已断开TCP连接');
                            uni.showToast({
                                title: '已断开连接',
                                icon: 'none'
                            });
                        }
                    });
                } else if (this.isConnected && (this.isMini || this.isH5)) {
                    // åŽç«¯ä¸­è½¬åœºæ™¯ï¼šé€šçŸ¥åŽç«¯æ–­å¼€
                    uni.request({
                        url: '/api/printer/disconnect'
                    });
                    this.isConnected = false;
                    this.addLog('已通知后端断开连接');
                    uni.showToast({
                        title: '已断开连接',
                        icon: 'none'
                    });
                }
            },
            // 3. å‘送ZPL指令(核心修改:直接发送二进制指令,替换Socket.io emit)
            sendZplCommand(zplCode, retry = 2) {
                return new Promise((resolve, reject) => {
                    // åŒºåˆ†APP直连和后端中转
                    if (this.isMini || this.isH5) {
                        // å°ç¨‹åº/H5:通过后端发送ZPL
                        uni.request({
                            url: this.backendPrintUrl,
                            method: 'POST',
                            data: {
                                ip: this.printerIP,
                                port: this.printerPort,
                                zplCode: zplCode
                            },
                            success: (res) => {
                                if (res.data.success) resolve(res.data);
                                else if (retry > 0) {
                                    this.addLog(`后端打印失败,重试(${retry}次)...`);
                                    setTimeout(() => this.sendZplCommand(zplCode, retry - 1).then(
                                        resolve).catch(reject), 1000);
                                } else reject(new Error(res.data.message || '后端打印失败'));
                            },
                            fail: (err) => reject(new Error(`后端请求失败:${err.errMsg}`))
                        });
                    } else {
                        // APP端:直接TCP发送ZPL(二进制格式)
                        if (!this.socketTask || !this.isConnected) {
                            reject(new Error('未建立TCP连接'));
                            return;
                        }
                        // ZPL指令转为Uint8Array(避免编码问题)
                        const buffer = new Uint8Array(Buffer.from(zplCode));
                        this.socketTask.send({
                            data: buffer,
                            success: () => {
                                this.addLog('ZPL指令发送成功');
                                resolve({
                                    success: true
                                });
                            },
                            fail: (err) => {
                                if (retry > 0) {
                                    this.addLog(`指令发送失败,重试(${retry}次)...`);
                                    setTimeout(() => this.sendZplCommand(zplCode, retry - 1).then(
                                        resolve).catch(reject), 1000);
                                } else reject(new Error(`发送失败:${err.errMsg}`));
                            }
                        });
                    }
                });
            },
            // 4. æž„建斑马ZPL指令(核心修改:适配中文、二维码)
            buildZpl(data, templateType) {
                const commands = new PrinterCommands(this.printerModel);
                // æ–‘马专用ZPL指令构建(覆盖PrinterCommands中对应方法)
                switch (templateType) {
                    case 'test':
                        // æµ‹è¯•页:含中文和简单文本(解决乱码)
                        return `^XA^CI28^CFSIMSUN,30^FO50,50^FD斑马打印机测试页(中文)^FS^FO50,100^FD当前时间:${new Date().toLocaleString()}^FS^XZ`;
                    case 'stockLabel':
                        // æˆå“å…¥åº“标签:含二维码(ZPL原生^BQ指令)
                        return `^XA
                            ^CI28^CFSIMSUN,24  // UTF-8编码 + ä¸­æ–‡å­—体(SIMSUN需提前上传到打印机)
                            ^FO30,30^FD订单号:${data.orderNo}^FS
                            ^FO30,70^FD客户:${data.customer}^FS
                            ^FO30,110^FD物料号:${data.materialNo}^FS
                            ^FO30,150^FD批次号:${data.batchNo}^FS
                            ^FO30,190^FD规格:${data.spec}^FS
                            ^FO30,230^FD数量:${data.quantity}ä»¶^FS
                            ^FO220,30^BQN,2,10  // äºŒç»´ç ï¼šQR Code,纠错等级2,大小10
                            ^FDQA,物料:${data.materialNo},批次:${data.batchNo}^FS  // QA前缀=QR Code,内容为物料+批次
                            ^XZ`.replace(/\s+/g, ''); // åŽ»é™¤å¤šä½™ç©ºæ ¼ï¼Œé¿å…è§£æžé”™è¯¯
                    case 'transferOrder':
                        // ç§»åº“单:类似入库标签,调整字段
                        return `^XA
                            ^CI28^CFSIMSUN,24
                            ^FO30,30^FD移库单号:${data.orderNo}^FS
                            ^FO30,70^FD客户:${data.customer}^FS
                            ^FO30,110^FD物料号:${data.materialNo}^FS
                            ^FO30,150^FD批次号:${data.batchNo}^FS
                            ^FO30,190^FD工厂:${data.factory}^FS
                            ^FO220,30^BQN,2,10
                            ^FDQA,移库单:${data.orderNo},数量:${data.quantity}^FS
                            ^XZ`.replace(/\s+/g, '');
                    case 'inspectionA':
                    case 'inspectionB':
                        // æ£€éªŒå•:多行检验项
                        let inspectionItems = '';
                        data.items.forEach((item, idx) => {
                            inspectionItems += `^FO30,${110 + idx * 40}^FD${item.name}:${item.result}^FS`;
                        });
                        return `^XA
                            ^CI28^CFSIMSUN,24
                            ^FO30,30^FD检验单号:${data.formNo}^FS
                            ^FO30,70^FD检验员:${data.inspector}^FS
                            ${inspectionItems}
                            ^FO220,30^BQN,2,10
                            ^FDQA,检验单:${data.formNo},物料:${data.materialNo}^FS
                            ^XZ`.replace(/\s+/g, '');
                    default:
                        throw new Error('未知模板类型');
                }
            },
            // æµ‹è¯•打印(ZPL指令)
            async testPrint() {
                try {
                    const zplCode = this.buildZpl({}, 'test');
                    await this.sendZplCommand(zplCode);
                    this.addLog('测试页打印成功(ZPL指令)');
                    uni.showToast({
                        title: '测试打印成功',
                        icon: 'success'
                    });
                } catch (error) {
                    this.addLog(`测试打印失败:${error.message}`);
                    uni.showToast({
                        title: '打印失败',
                        icon: 'none'
                    });
                }
            },
            // æ‰“印成品入库标签(使用ZPL)
            async printStockLabel() {
                try {
                    const data = {
                        orderNo: '11263797',
                        customer: '吉利',
                        model: '6608268440',
                        materialNo: '120026829',
                        batchNo: '25219773',
                        spec: 'G3-700A',
                        quantity: 100,
                        date: '2023/06/07'
                    };
                    const zplCode = this.buildZpl(data, 'stockLabel');
                    await this.sendZplCommand(zplCode);
                    this.addLog('成品入库标签打印成功');
                    uni.showToast({
                        title: '打印成功',
                        icon: 'success'
                    });
                } catch (error) {
                    this.addLog(`打印失败:${error.message}`);
                    uni.showToast({
                        title: '打印失败',
                        icon: 'none'
                    });
                }
            },
            // æ‰“印移库单(使用ZPL)
            async printTransferOrder() {
                try {
                    const data = {
                        orderNo: '112379',
                        productModel: 'G-639',
                        customer: '东方日产',
                        materialNo: '120047854',
                        customerModel: '4200-51354',
                        batchNo: '25159847',
                        factory: '双林新火炬工厂',
                        quantity: 73
                    };
                    const zplCode = this.buildZpl(data, 'transferOrder');
                    await this.sendZplCommand(zplCode);
                    this.addLog('移库单打印成功');
                    uni.showToast({
                        title: '打印成功',
                        icon: 'success'
                    });
                } catch (error) {
                    this.addLog(`打印失败:${error.message}`);
                    uni.showToast({
                        title: '打印失败',
                        icon: 'none'
                    });
                }
            },
            // æ‰“印检验单(使用ZPL)
            async printInspectionForm(type) {
                try {
                    const data = {
                        formNo: type === 1 ? 'JYD-20250801' : 'JYD-20250802',
                        materialNo: '120026829',
                        batchNo: '25219773',
                        inspector: '张三',
                        date: new Date().toLocaleDateString(),
                        items: [{
                                name: '外观',
                                result: '合格'
                            },
                            {
                                name: '尺寸',
                                result: '合格'
                            },
                            {
                                name: '性能',
                                result: type === 1 ? '合格' : '待检'
                            }
                        ]
                    };
                    const zplCode = this.buildZpl(data, `inspection${type === 1 ? 'A' : 'B'}`);
                    await this.sendZplCommand(zplCode);
                    this.addLog(`检验单${type}打印成功`);
                    uni.showToast({
                        title: '打印成功',
                        icon: 'success'
                    });
                } catch (error) {
                    this.addLog(`打印失败:${error.message}`);
                    uni.showToast({
                        title: '打印失败',
                        icon: 'none'
                    });
                }
            }
        }
    }
        }
    };
</script>
<style>
</style>
<style scoped>
    .platform-tip {
        color: #FF3B30;
        font-size: 24rpx;
        margin-bottom: 15rpx;
        padding: 10rpx;
        background-color: #FFF8F8;
        border-radius: 8rpx;
    }
    .btn.primary-outline {
        background-color: #fff;
        color: #007AFF;
        border: 1rpx solid #007AFF;
    }
    .container {
        padding-bottom: 20rpx;
    }
    .setting-area,
    .print-area {
        padding: 20rpx;
        background-color: #fff;
        margin: 10rpx;
        border-radius: 10rpx;
    }
    .input-item {
        display: flex;
        align-items: center;
        margin-bottom: 20rpx;
        border-bottom: 1rpx solid #eee;
        padding-bottom: 10rpx;
    }
    .input-item text {
        width: 140rpx;
        font-size: 28rpx;
        color: #333;
    }
    .uni-easyinput {
        flex: 1;
    }
    .btn {
        width: 100%;
        padding: 20rpx;
        margin-bottom: 15rpx;
        border-radius: 8rpx;
        color: #fff;
        font-size: 28rpx;
    }
    .primary {
        background-color: #007AFF;
    }
    .danger {
        background-color: #FF3B30;
    }
    .print {
        background-color: #00C853;
    }
    .test {
        background-color: #FF9500;
    }
    .print-title {
        display: block;
        font-size: 28rpx;
        color: #666;
        margin-bottom: 15rpx;
    }
    .status {
        padding: 20rpx;
        font-size: 28rpx;
        color: #666;
    }
    .log {
        margin: 10rpx;
        padding: 20rpx;
        background-color: #f5f5f5;
        border-radius: 10rpx;
    }
    .log-title {
        font-weight: bold;
        display: block;
        margin-bottom: 10rpx;
        color: #333;
    }
    .log-item {
        font-size: 26rpx;
        color: #666;
        margin-bottom: 5rpx;
        word-break: break-all;
    }
</style>
pages/user/people.vue
@@ -48,6 +48,18 @@
                    <text class="text-grey">定位</text>
                </view>
            </navigator> -->
            <navigator class="cu-item arrow animation-slide-bottom" :style="[{animationDelay: '0.4s'}]" url="/pages/user/location" hover-class="none">
                <view class="content" >
                    <text class="cuIcon-news text-cyan"></text>
                    <text class="text-grey">打印机</text>
                </view>
            </navigator>
            <navigator class="cu-item arrow animation-slide-bottom" :style="[{animationDelay: '0.4s'}]" url="/pages/lineSelect/lineSelect" hover-class="none">
                <view class="content" >
                    <text class="cuIcon-location text-cyan"></text>
                    <text class="text-grey">产线</text>
                </view>
            </navigator>
            <navigator class="cu-item arrow animation-slide-bottom" url="/pages/user/userdetail" :style="[{animationDelay: '0.6s'}]">
                 <view class="content">
                    <text class="cuIcon-settingsfill text-cyan"></text>
store/index.js
@@ -3,172 +3,259 @@
import api from "@/api/api"
import MinCache from '@/common/util/MinCache.js'
import {
    ACCESS_TOKEN,
    USER_NAME,
    USER_INFO,
    X_TENANT_ID
  ACCESS_TOKEN,
  USER_NAME,
  USER_INFO,
  X_TENANT_ID
} from "@/common/util/constants"
Vue.use(Vuex)
export default new Vuex.Store({
    state: {
        auth: [],
        token: '',
        userid: '',
        username: '',
        realname: '',
        welcome: '',
        avatar: ''
    },
    mutations: {
        SET_AUTH(state, auth) {
            state.auth = auth
        },
        SET_TOKEN: (state, token) => {
            state.token = token
        },
        SET_NAME: (state, {
            username,
            realname,
            welcome
        }) => {
            state.username = username
            state.realname = realname
            state.welcome = welcome
        },
        SET_AVATAR: (state, avatar) => {
            state.avatar = avatar
        }
    },
    actions: {
        // ç™»å½•
        mLogin({
            commit
        }, userInfo) {
            return new Promise((resolve, reject) => {
                api.login(userInfo).then(response => {
                    if (response.data.code == 200) {
                        const result = response.data.result
                        const userInfo = result.userInfo
                        uni.setStorageSync(ACCESS_TOKEN, result.token);
                        uni.setStorageSync("isLogin", true);
                        uni.setStorageSync("userId", userInfo.id);
                        uni.setStorageSync(USER_INFO, userInfo);
                        commit('SET_TOKEN', result.token)
                        commit('SET_AVATAR', userInfo.avatar)
                        commit('SET_NAME', {
                            username: userInfo.username,
                            realname: userInfo.realname
                        })
                        resolve(response)
                    } else {
                        resolve(response)
                    }
                }).catch(error => {
                    console.log("catch===>response", response)
                    reject(error)
                })
            })
        },
        //手机号登录
        PhoneLogin({
            commit
        }, userInfo) {
            return new Promise((resolve, reject) => {
                api.phoneNoLogin(userInfo).then(response => {
                    if (response.data.code == 200) {
                        const result = response.data.result
                        const userInfo = result.userInfo
                        uni.setStorageSync(ACCESS_TOKEN, result.token);
                        uni.setStorageSync(USER_INFO, userInfo);
                        commit('SET_TOKEN', result.token)
                        commit('SET_NAME', {
                            username: userInfo.username,
                            realname: userInfo.realname
                        })
                        commit('SET_AVATAR', userInfo.avatar)
                        resolve(response)
                    } else {
                        reject(response)
                    }
                }).catch(error => {
                    reject(error)
                })
            })
        },
        // ç¬¬ä¸‰æ–¹ç™»å½•
        ThirdLogin({
            commit
        }, param) {
            return new Promise((resolve, reject) => {
                api.thirdLogin(param.token, param.thirdType).then(response => {
                    if (response.data.code == '200') {
                        const result = response.data.result
                        const userInfo = result.userInfo
                        uni.setStorageSync(ACCESS_TOKEN, result.token);
                        uni.setStorageSync(USER_INFO, userInfo);
                        uni.setStorageSync("userId", userInfo.id);
                        uni.setStorageSync(X_TENANT_ID, userInfo.loginTenantId);
  state: {
    auth: [],
    token: '',
    userid: '',
    username: '',
    realname: '',
    welcome: '',
    avatar: '',
    user: {}, // è¡¥å……用户信息对象
    tenantId: '', // è¡¥å……租户ID
    // äº§çº¿ç®¡ç†ç›¸å…³çŠ¶æ€
    lineList: [], // äº§çº¿åˆ—表
    currentLineId: uni.getStorageSync('currentLineId') || null, // å½“前选中的产线ID
    currentLineName: uni.getStorageSync('currentLineName') || '', // å½“前选中的产线名称
    currentLineInfo: null, // å½“前选中的产线详细信息
    currentLineType: uni.getStorageSync('currentLineType') || '' // æ–°å¢žï¼šå½“前选中的产线类型
  },
  mutations: {
    SET_AUTH(state, auth) {
      state.auth = auth
    },
    SET_TOKEN: (state, token) => {
      state.token = token
    },
    SET_NAME: (state, {
      username,
      realname,
      welcome
    }) => {
      state.username = username
      state.realname = realname
      state.welcome = welcome
    },
    SET_AVATAR: (state, avatar) => {
      state.avatar = avatar
    },
    SET_ID: (state, id) => {
      state.userid = id
    },
    SET_INFO: (state, userInfo) => {
      state.user = userInfo
    },
    SET_TENANTID: (state, tenantId) => {
      state.tenantId = tenantId
    },
    // äº§çº¿ç›¸å…³mutations
    SET_LINE_LIST(state, list) {
      state.lineList = list
      console.log('Vuex SET_LINE_LIST: äº§çº¿åˆ—表已更新', list);
    },
    SET_CURRENT_LINE_ID(state, lineId) {
      state.currentLineId = lineId
      uni.setStorageSync('currentLineId', lineId)
                        commit('SET_TOKEN', result.token)
                        commit('SET_AVATAR', userInfo.avatar)
                        commit('SET_NAME', {
                            username: userInfo.username,
                            realname: userInfo.realname
                        })
                        commit('SET_ID', userInfo.id)
                        commit('SET_INFO', userInfo)
                        commit('SET_TENANTID', userInfo.loginTenantId)
                        resolve(response)
                    } else {
                        reject(response)
                    }
                }).catch(error => {
                    reject(error)
                })
            })
        },
        // ç™»å‡º
        Logout({
            commit,
            state
        }) {
            return new Promise((resolve) => {
                let logoutToken = state.token;
                commit('SET_TOKEN', '')
                uni.removeStorageSync(ACCESS_TOKEN)
                api.logout(logoutToken).then(() => {
                    resolve()
                }).catch(() => {
                    resolve()
                })
            })
        },
        saveAuth({
            commit
        }, auth) {
            commit('SET_AUTH', auth)
        }
    },
    getters: {
        getAuth: state => state.auth,
        token: state => state.token,
        username: state => {
            state.userid = uni.getStorageSync(USER_INFO).username;
            return state.username
        },
        nickname: state => {
            state.userid = uni.getStorageSync(USER_INFO).realname;
            return state.user.realname
        },
        avatar: state => {
            state.userid = uni.getStorageSync(USER_INFO).avatar;
            return state.user.avatar
        },
        userid: state => {
            state.userid = uni.getStorageSync(USER_INFO).id;
            return state.userid
        },
    }
      // åŒæ­¥æ›´æ–°å½“前产线信息、名称和类型
      if (lineId && state.lineList.length > 0) {
        state.currentLineInfo = state.lineList.find(line => line.id === lineId) || null
        // ä»Žäº§çº¿ä¿¡æ¯ä¸­æå–名称并保存
        state.currentLineName = state.currentLineInfo ? state.currentLineInfo.name : ''
        // æ–°å¢žï¼šä»Žäº§çº¿ä¿¡æ¯ä¸­æå–类型并保存
        state.currentLineType = state.currentLineInfo ? state.currentLineInfo.type : ''
        uni.setStorageSync('currentLineName', state.currentLineName)
        // æ–°å¢žï¼šå°†ç±»åž‹åŒæ­¥ä¿å­˜åˆ°æœ¬åœ°å­˜å‚¨
        uni.setStorageSync('currentLineType', state.currentLineType)
      } else {
        state.currentLineInfo = null
        state.currentLineName = ''
        state.currentLineType = '' // æ–°å¢žï¼šæ¸…空类型
        uni.removeStorageSync('currentLineName')
        uni.removeStorageSync('currentLineType') // æ–°å¢žï¼šæ¸…除本地存储的类型
      }
      console.log('Vuex SET_CURRENT_LINE_ID: å½“前产线ID已更新', lineId);
      console.log('Vuex SET_CURRENT_LINE_NAME: å½“前产线名称已更新', state.currentLineName);
      console.log('Vuex SET_CURRENT_LINE_TYPE: å½“前产线类型已更新', state.currentLineType); // æ–°å¢žï¼šæ‰“印类型信息
    }
  },
  actions: {
    // è´¦å·ç™»å½•
    mLogin({
      commit
    }, userInfo) {
      return new Promise((resolve, reject) => {
        api.login(userInfo).then(response => {
          if (response.data.code == 200) {
            const result = response.data.result
            const userInfo = result.userInfo
            uni.setStorageSync(ACCESS_TOKEN, result.token);
            uni.setStorageSync("isLogin", true);
            uni.setStorageSync("userId", userInfo.id);
            uni.setStorageSync(USER_INFO, userInfo);
            commit('SET_TOKEN', result.token)
            commit('SET_AVATAR', userInfo.avatar)
            commit('SET_NAME', {
              username: userInfo.username,
              realname: userInfo.realname
            })
            commit('SET_ID', userInfo.id)
            commit('SET_INFO', userInfo)
            resolve(response)
          } else {
            resolve(response)
          }
        }).catch(error => {
          console.log("登录失败:", error)
          reject(error)
        })
      })
    },
    // æ‰‹æœºå·ç™»å½•
    PhoneLogin({
      commit
    }, userInfo) {
      return new Promise((resolve, reject) => {
        api.phoneNoLogin(userInfo).then(response => {
          if (response.data.code == 200) {
            const result = response.data.result
            const userInfo = result.userInfo
            uni.setStorageSync(ACCESS_TOKEN, result.token);
            uni.setStorageSync(USER_INFO, userInfo);
            commit('SET_TOKEN', result.token)
            commit('SET_NAME', {
              username: userInfo.username,
              realname: userInfo.realname
            })
            commit('SET_AVATAR', userInfo.avatar)
            commit('SET_ID', userInfo.id)
            commit('SET_INFO', userInfo)
            resolve(response)
          } else {
            reject(response)
          }
        }).catch(error => {
          reject(error)
        })
      })
    },
    // ç¬¬ä¸‰æ–¹ç™»å½•
    ThirdLogin({
      commit
    }, param) {
      return new Promise((resolve, reject) => {
        api.thirdLogin(param.token, param.thirdType).then(response => {
          if (response.data.code == '200') {
            const result = response.data.result
            const userInfo = result.userInfo
            uni.setStorageSync(ACCESS_TOKEN, result.token);
            uni.setStorageSync(USER_INFO, userInfo);
            uni.setStorageSync("userId", userInfo.id);
            uni.setStorageSync(X_TENANT_ID, userInfo.loginTenantId);
            commit('SET_TOKEN', result.token)
            commit('SET_AVATAR', userInfo.avatar)
            commit('SET_NAME', {
              username: userInfo.username,
              realname: userInfo.realname
            })
            commit('SET_ID', userInfo.id)
            commit('SET_INFO', userInfo)
            commit('SET_TENANTID', userInfo.loginTenantId)
            resolve(response)
          } else {
            reject(response)
          }
        }).catch(error => {
          reject(error)
        })
      })
    },
    // ç™»å‡º
    Logout({
      commit,
      state
    }) {
      return new Promise((resolve) => {
        let logoutToken = state.token;
        commit('SET_TOKEN', '')
        uni.removeStorageSync(ACCESS_TOKEN)
        uni.removeStorageSync("isLogin")
        uni.removeStorageSync("userId")
        // æ¸…除产线选择状态
        commit('SET_CURRENT_LINE_ID', null)
        api.logout(logoutToken).then(() => {
          resolve()
        }).catch(() => {
          resolve()
        })
      })
    },
    saveAuth({
      commit
    }, auth) {
      commit('SET_AUTH', auth)
    },
    // èŽ·å–äº§çº¿åˆ—è¡¨ï¼ˆå·²åŒ…å«type字段)
    fetchLineList({ commit, state }) {
      return new Promise((resolve, reject) => {
        api.getLineList({
          headers: {
            'Authorization': `Bearer ${state.token}`
          }
        }).then(response => {
          console.log('fetchLineList接口返回原始数据:', response);
          if (response.data.code === 200) {
            const lineList = (response.data.result || []).map(line => ({
              id: line.value,
              name: line.text,
              type: line.type // ç¡®ä¿æ˜ å°„type字段
            }));
            commit('SET_LINE_LIST', lineList);
            resolve(lineList);
          } else {
            reject(new Error(`获取产线列表失败: ${response.data.message || '未知错误'}`));
          }
        }).catch(error => {
          console.error('获取产线列表出错:', error);
          reject(error);
        });
      });
    },
    // è®¾ç½®å½“前产线(保持不变,类型通过mutation自动同步)
    setCurrentLine({ commit }, lineId) {
      return new Promise((resolve) => {
        commit('SET_CURRENT_LINE_ID', lineId)
        resolve()
      })
    }
  },
  getters: {
    getAuth: state => state.auth,
    token: state => state.token,
    username: state => state.username || uni.getStorageSync(USER_INFO)?.username || '',
    nickname: state => state.realname || uni.getStorageSync(USER_INFO)?.realname || '',
    avatar: state => state.avatar || uni.getStorageSync(USER_INFO)?.avatar || '',
    userid: state => state.userid || uni.getStorageSync(USER_INFO)?.id || '',
    // äº§çº¿ç›¸å…³getters
    lineList: state => state.lineList,
    currentLineId: state => state.currentLineId,
    currentLineName: state => state.currentLineName,
    currentLineInfo: state => state.currentLineInfo,
    currentLineType: state => state.currentLineType, // æ–°å¢žï¼šèŽ·å–å½“å‰äº§çº¿ç±»åž‹çš„getter
    hasSelectedLine: state => !!state.currentLineId
  }
})