Commit 488d0d0d by 李宁

1

1 parent 2909ba24
Showing 73 changed files with 3200 additions and 0 deletions
怀化需求项目代码
需求文档地址:https://jfq5tn3wbn.feishu.cn/docx/MSTQdIGwho4jLLxDsCOcJdhcnDg
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>怀化移动</title>
<link rel="stylesheet" href="css/vant.css"/>
<link rel="stylesheet" href="css/addOrder.css?123123">
</head>
<body>
<div id="pageDiv" class="pageDiv">
<div class="infoTop">
<div class="status">{{info.address}}</div>
<div class="detail">
<div class="detli">
<div class="detL">装维ID</div>
<div>{{info.campaignId}}</div>
</div>
<div class="detli">
<div class="detL">业务账号</div>
<div>{{info.accNbr}}</div>
</div>
</div>
</div>
<div class="orderList">
<div class="orderli" v-for="(item,index) in orderArr">
<div class="ortil">添加工单{{index+1}}</div>
<div class="orcon">
<div class="orcli">
<div class="ortype">工单ID</div>
<input type="text" v-model="item.orderCode" placeholder="请输入">
</div>
<div class="orcli">
<div class="ortype">工单类型</div>
<div class="chose" @click="pickShow('',index)">
<div :class="{black:item.serviceName}">{{item.serviceName||'请选择'}}</div>
<img src="https://xpo.oss-cn-beijing.aliyuncs.com/huaian/right.png" alt="">
</div>
</div>
<div class="orcli">
<div class="ortype">添加设备</div>
<div class="chose" @click="pickShow('device',index)">
<div :class="{black:item.terminalClass}">{{item.terminalClass||'请选择'}}</div>
<img src="https://xpo.oss-cn-beijing.aliyuncs.com/huaian/right.png" alt="">
</div>
</div>
<div class="orcli">
<div class="ortype">设备串号</div>
<input type="text" v-model="item.deviceNumber" placeholder="请输入">
</div>
</div>
</div>
</div>
<div class="addDiv" @click="addOrder">
<img src="https://xpo.oss-cn-beijing.aliyuncs.com/huaian/add.png" alt="">
<div>添加工单</div>
</div>
<div class="botButt" @click="goSave">保存</div>
<div class="outAlert pickAlert" v-show="pickData.isShow">
<van-picker
show-toolbar
:title="pickData.title"
:columns="pickData.arr"
:default-index="pickData.dIndex"
@cancel="onCancel"
@confirm="onConfirm"
/>
</div>
<div class="outAlert" v-if="confirmFlag">
<div class="alertCon">
<div class="info">请确保工单号输入正确,否则会影响后续质检</div>
<div class="butt">
<div class="left" @click="confirmFlag=false">返回</div>
<div class="right" @click="saveOrder">确认并提交</div>
</div>
</div>
</div>
</div>
<script src="js/axios.min.js"></script>
<script src="js/vue.min.js"></script>
<script src="js/vant.min.js"></script>
<script src="js/util.js?12312313"></script>
<script src="js/addOrder.js?00"></script>
</body>
</html>
\ No newline at end of file
html{
font-size: calc(100vw/7.5) ;
}
html,body{
width: 100%;
min-height: 100%;
}
*{
margin: 0;
padding: 0;
}
div{
line-height: 1;
box-sizing: border-box;
}
.pageDiv{
width: 100%;
min-height: calc(100vh);
padding-top: .52rem;
background: #F7F8FA;
padding: .24rem;
padding-bottom: 1.2rem;
display: none;
}
.infoTop{
background: #fff;
border-radius: .08rem;
background: #FFF;
padding: .48rem .32rem;
padding-bottom: .2rem;
margin-bottom: .2rem;
}
.infoTop .status{
color: #333;
font-weight: bold;
font-size: .4rem;
margin-bottom: .32rem;
line-height: .52rem;
}
.infoTop .detail .detli{
display: flex;
color: #333;
font-size: .32rem;
margin-bottom: .28rem;
}
.infoTop .detail .detli .detL{
color: #666;
margin-right: .4rem;
}
.orderList .orderli{
margin-bottom: .2rem;
border-radius: 4px;
background: #FFF;
}
.orderList .orderli .ortil{
color: #333;
font-size: .34rem;
font-weight: 500;
padding: .32rem;
width: 6.7rem;
}
.orderList .orderli .orcon{
padding: 0 .16rem;
}
.orderList .orderli .orcon .orcli{
display: flex;
color: #333;
padding: .32rem .16rem;
font-size: .32rem;
border-top: 1px solid #F6F6F6;
}
.orderList .orderli .orcon .orcli .ortype{
color: #666;
margin-right: .4rem;
flex-shrink: 0;
width: 1.28rem;
}
.orderList .orderli .orcon .orcli input{
border: none;
outline-style: none;
}
.orderList .orderli .orcon .orcli input::placeholder{
color: #999;
font-size: .32rem;
}
.orderList .orderli .orcon .orcli .chose{
display: flex;
color: #999;
justify-content: space-between;
flex-grow: 1;
align-items: center;
}
.orderList .orderli .orcon .orcli .chose img{
width: .32rem;
height: .32rem;
}
.orderList .orderli .orcon .orcli .chose .black{
color: #333;
}
.addDiv{
display: flex;
align-items: center;
justify-content: center;
border-radius: .08rem;
border: 1px dashed #568FFE;
background: #FFF;
height: .88rem;
color: #568FFE;
font-size: .34rem;
font-weight: 500;
}
.addDiv img{
width: .32rem;
height: .32rem;
margin-right: .08rem;
}
.botButt{
position: fixed;
width: 7.02rem;
height: .88rem;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
border-radius: .08rem;
background: #568FFE;
font-weight: 500;
font-size: .34rem;
left: .24rem;
z-index: 9;
bottom: 0;
}
.outAlert{
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
background: rgba(0, 0, 0, 0.70);
z-index: 99;
}
.outAlert .alertCon{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
background: #fff;
border-radius: .2rem;
width: 5.6rem;
}
.outAlert .alertCon .info{
color: #333;
font-size: .32rem;
text-align: center;
padding: .4rem;
padding-top: .56rem;
border-bottom: 1px solid #F6F6F6;
line-height: 1.5;
}
.outAlert .alertCon .butt{
display: flex;
color: #999;
font-size: .34rem;
}
.outAlert .alertCon .butt div{
width: 50%;
height: .98rem;
display: flex;
justify-content: center;
align-items: center;
}
.outAlert .alertCon .butt .right{
color: #568FFE;
border-left: 1px solid #F6F6F6;
}
.pickAlert{
display: flex;
align-items: flex-end;
}
.pickAlert .van-picker{
width: 100%;
}
.pickAlert .van-picker__title{
line-height: 44px;
}
\ No newline at end of file
html{
font-size: calc(100vw/7.5) ;
}
html,body{
width: 100%;
height: 100%;
}
*{
margin: 0;
padding: 0;
font-family: 'Source Han Sans', sans-serif;
box-sizing: border-box;
}
div{
line-height: 1;
}
[v-cloak] {
display: none !important;
}
.list-container {
height: 100vh;
display: flex;
flex-direction: column;
background: #F7F8FA;
}
.tabs {
display: flex;
background: #F3F6FF;
padding: 0 .24rem;
justify-content: space-between;
align-items: center;
}
.tabs .left{
display: flex;
}
.tabs .right{
font-size: .28rem;
color: #333;
font-weight: 500;
width: 1.56rem;
height: .6rem;
line-height: .6rem;
border-radius: .48rem;
background: #E1EBFE;
text-align: center;
}
.tab-item {
padding: .28rem .3rem;
font-size: .36rem;
color: #333;
cursor: pointer;
position: relative;
margin-right: .4rem;
transition: all 0.3s;
font-weight: 500;
}
.tab-item.active {
color: #007bff;
font-weight: 700;
}
.tab-item.active::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 30%;
height: .08rem;
background-color: #007bff;
}
.tab-item:hover {
color: #007bff;
}
.search-section {
padding: .2rem;
background: #F3F6FF;
}
.search-box {
position: relative;
display: flex;
align-items: center;
background: white;
border: 1px solid #ddd;
border-radius: .08rem;
padding: .2rem .24rem;
transition: border-color 0.3s;
font-size: .28rem;
color: #999;
}
.search-box:focus-within {
border-color: #007bff;
}
.search-icon {
width: .32rem;
height: .32rem;
margin-right: .16rem;
opacity: 0.6;
}
.search-input {
flex: 1;
border: none;
background: transparent;
font-size: .28rem;
outline: none;
}
.search-input::placeholder {
color: #999;
}
.list-section {
flex: 1;
overflow-y: auto;
padding: .24rem;
}
.list-item {
display: flex;
align-items: flex-start;
padding: .36rem .24rem;
background: white;
border-radius: .16rem;
margin-bottom: .2rem;
}
.item-content {
flex: 1;
min-width: 0;
}
.item-row {
display: flex;
align-items: center;
margin-bottom: .26rem;
}
.item-row:last-child {
margin-bottom: 0;
}
.item-icon-small {
width: .32rem;
height: .32rem;
margin-right: .16rem;
flex-shrink: 0;
}
.item-desc {
font-size: .28rem;
color: #333;
line-height: .4rem;
}
.empty-state {
text-align: center;
padding: 1rem .4rem;
color: #999;
font-size: .32rem;
}
\ No newline at end of file
html{
font-size: calc(100vw/7.5) ;
}
html,body{
width: 100%;
height: 100%;
}
*{
margin: 0;
padding: 0;
font-family: 'Source Han Sans', sans-serif;
box-sizing: border-box;
}
div{
line-height: 1;
}
[v-cloak] {
display: none !important;
}
.login-contalogoiner {
height: 100vh;
display: flex;
flex-direction: column;
}
.header-section {
height: 4.6rem;
position: relative;
}
.background-image {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
.background-image .bg {
width: 100%;
height: 100%;
object-fit: cover;
}
.header-content {
position: absolute;
top: 50%;
left: .42rem;
transform: translateY(-50%);
color: #333;
font-size: .32rem;
}
.logo {
width: .8rem;
height: .8rem;
display: block;
}
.header-content .hello{
width: 1.6rem;
height: .46rem;
margin: .28rem 0;
}
.header-content .name{
font-weight: 500;
}
.login-form {
background: white;
padding: .64rem .48rem;
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
}
.input-group {
display: flex;
align-items: center;
margin-bottom: .48rem;
border: 1px solid #ddd;
border-radius: .16rem;
height: .96rem;;
background: #f9f9f9;
padding-left: .32rem;
font-size: .32rem;
}
.input-group:focus-within {
border-color: #007bff;
}
.input-icon {
width: .4rem;
height: .4rem;
flex-shrink: 0;
margin-right: .16rem;
}
.input-field {
flex: 1;
border: none;
background: transparent;
font-size: .32rem;
outline: none;
}
.input-field::placeholder {
color: #999;
}
.verify-btn {
color: #007bff;
font-size: .32rem;
margin-right: .4rem;
}
.verify-btn:disabled {
background: #ccc;
cursor: not-allowed;
}
.login-btn {
background: #007bff;
color: white;
border: none;
padding: .32rem;
border-radius: .16rem;
font-size: .32rem;
font-weight: bold;
cursor: pointer;
margin-top: .48rem;
transition: background-color 0.3s;
}
.login-btn:hover {
background: #0056b3;
}
\ No newline at end of file
html{
font-size: calc(100vw/7.5) ;
}
html,body{
width: 100%;
height: 100%;
}
*{
margin: 0;
padding: 0;
}
div{
line-height: 1;
box-sizing: border-box;
}
.pageDiv{
width: 100%;
height: 100%;
padding-top: .52rem;
background: #F7F8FA;
padding: .24rem;
padding-bottom: 1.2rem;
display: none;
}
.infoTop{
background: #fff;
border-radius: .08rem;
background: #FFF;
padding: .48rem .32rem;
margin-bottom: .48rem;
padding-top: .8rem;
}
.infoTop .icon{
width: 1.28rem;
height: 1.28rem;
display: block;
margin: auto;
}
.infoTop .status{
color: #333;
font-weight: bold;
font-size: .4rem;
margin-bottom: .8rem;
text-align: center;
margin-top: .32rem;
}
.infoTop .detail .detli{
display: flex;
color: #333;
font-size: .32rem;
margin-bottom: .28rem;
justify-content: space-between;
}
.infoTop .detail .detli .detL{
color: #666;
margin-right: .4rem;
width: 1.5rem;
flex-shrink: 0;
}
.infoTop .detail .detli .detR{
text-align: right;
line-height: 1.2;
}
.botButt{
width: 3.38rem;
height: .88rem;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
border-radius: .08rem;
background: #568FFE;
font-weight: 500;
font-size: .34rem;
z-index: 9;
margin: auto;
}
\ No newline at end of file
This diff could not be displayed because it is too large.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>怀化移动</title>
<link rel="stylesheet" href="https://xpo.oss-cn-beijing.aliyuncs.com/huaian/css/vant.css"/>
<link rel="stylesheet" href="css/index.css?90909090">
</head>
<body>
<!-- <script>
if(!location.href.includes('reloadTime')){
window.location.replace(location.href + '&reloadTime='+ new Date().getTime())
}
</script> -->
<div id="pageDiv" class="pageDiv" :class="{pageDone:detail.finish=='1'}">
<img class="bgImg" src="https://xpo.oss-cn-beijing.aliyuncs.com/huaian/bg.png" alt="">
<div class="tsDiv" v-if="detail.finish!='1'">
<img src="https://xpo.oss-cn-beijing.aliyuncs.com/huaian/tanhao2.png" alt="">
<div>手写账号数字请规整,避免识别出错</div>
</div>
<div class="topText">
<div class="tleft">
<div class="tup">质检{{detail.finish=='1'?'已完成':'待完成'}}</div>
<div class="tdown">
<div class="tdli" v-for="item in tarr">
<img src="https://xpo.oss-cn-beijing.aliyuncs.com/huaian/duihao.png" alt="">
<div>{{item}}</div>
</div>
</div>
</div>
<div class="tright">
<img src="https://xpo.oss-cn-beijing.aliyuncs.com/huaian/number.png" alt="">
</div>
</div>
<div class="infoDiv">
<div class="infoTop">
<div class="detail">
<div class="detli">{{detail.accNbr}}</div>
<div class="detli">地址:{{detail.addressName||'--'}}</div>
</div>
</div>
<div class="orderList">
<div class="orderli" v-for="(item,index) in detail.devicessList
">
<div class="ortil">
<div class="gdid">工单{{index+1}}:{{item.orderCode}}</div>
<div class="icon" v-show="item.isLocal==1">手动录入</div>
</div>
<div class="orcon">
<div class="orcli">
<div class="ortype">工单类型</div>
<div>{{item.serviceName}}</div>
</div>
<div class="orcli" v-if="item.terminalClass">
<div class="ortype">装机装备</div>
<div>{{item.terminalClass}}</div>
</div>
</div>
<div class="button" v-show="item.isLocal==1 && detail.finish!='1'">
<div @click="delOrder(index)">删除</div>
</div>
</div>
</div>
<div class="infoTs" v-if="detail.finish!='1'">
<div class="infoLi" v-if="appParam.processType!='complaint'">
<div>工单未同步?查看</div>
<div class="blue" @click="orderError">解决办法</div>
</div>
<div v-if="appParam.processType!='complaint'"></div>
<div class="infoLi">
<div>无法质检?</div>
<div class="blue" @click="feedback">我要反馈</div>
</div>
</div>
</div>
<div v-if="detail.finish!='1'" class="botButt">
<div @click="beginTest">开始质检</div>
</div>
<div class="outAlert" v-if="orderFlag">
<div class="alertCon orderCon">
<div class="til">工单没有同步?</div>
<div class="conli">1、方案一:因系统与crm系统对接有延时,你可十分钟后再进行质检</div>
<div class="conli" @click="addOrder">2、方案二:自行 <span>添加工单>></span></div>
<div class="know" @click="closeAlert">我知道了</div>
</div>
</div>
<div class="outAlert" v-if="fbData.isShow">
<div class="alertCon modifyAddreCon noTestCon">
<div class="til">我要反馈</div>
<div class="topTs">如你出现无法质检的情况,比如摄像头不能用,用户不让拍摄的情况,你可填写原因和情况说明跳过质检</div>
<div class="cli" @click="showReason">
<div class="ctil">
<img src="https://xpo.oss-cn-beijing.aliyuncs.com/huaian/xing.png" alt="">
<div>原因</div>
</div>
<div class="chose" :class="{hcho: reasonPickData.reason}">
<div>{{reasonPickData.reason?reasonPickData.reason:'选择原因'}}</div>
<img src="https://xpo.oss-cn-beijing.aliyuncs.com/huaian/arrowDown.png" alt="">
</div>
</div>
<div class="cli">
<div class="ctil">
<img src="https://xpo.oss-cn-beijing.aliyuncs.com/huaian/xing.png" alt="">
<div>情况说明</div>
</div>
<textarea placeholder="请填写具体情况" v-model="fbData.explain"></textarea>
</div>
<div class="know" @click="fbData.confirmFlag=true">保存</div>
<div class="botTs">提交反馈后管理员会尽快审核检查,并且您无法再次进行质检</div>
<img class="close" src="https://xpo.oss-cn-beijing.aliyuncs.com/huaian/close.png" @click="fbData.isShow=false">
</div>
</div>
<div class="outAlert" v-if="fbData.confirmFlag">
<div class="feedbackConfirmCon">
<div class="info">确定提交?提交后不可再次进行质检</div>
<div class="butt">
<div class="left" @click="fbData.confirmFlag=false">取消</div>
<div class="right" @click="saveFeedback">确定并提交</div>
</div>
</div>
</div>
<div class="outAlert pickAlert" v-if="pickData.isShow">
<van-picker
show-toolbar
:title="pickData.title"
:columns="pickData.arr"
@change="onChange"
@cancel="onCancel"
@confirm="onConfirm"
/>
</div>
<div class="outAlert pickAlert" v-if="reasonPickData.isShow">
<van-picker
show-toolbar
:title="reasonPickData.title"
:columns="reasonPickData.arr"
:default-index="reasonPickData.index"
@cancel="reasonCancel"
@confirm="reasonConfirm"
/>
</div>
<div class="noData" v-if="noDataFlag">
<img src="https://xpo.oss-cn-beijing.aliyuncs.com/huaian/noData.png?0909090" alt="">
</div>
</div>
<img id="loading" class="loading" src="https://xpo.oss-cn-beijing.aliyuncs.com/huaian/loading.svg" alt="">
<script src="js/axios.min.js"></script>
<script src="js/vue.min.js"></script>
<script src="js/vant.min.js"></script>
<script src="js/util.js?11111"></script>
<script src="js/index.js?1255333"></script>
</body>
</html>
\ No newline at end of file
This diff could not be displayed because it is too large.
(function($$) {
"use strict";
let vm
const util = new window.publicMethod() ;
function init() {
vm = new Vue({
el: '#pageDiv',
data: {
info: {},
confirmFlag: false,
typeArr: [],
deviceArr: [],
pickData: {
isShow: false,
title: '',
typeIndex: 0,
deviceIndex: 0,
dIndex: 0,
ntype: '',
index: 0,
arr: []
},
orderArr: []
},
created: function() {
this.info = JSON.parse(sessionStorage.getItem('huaiAnAppParam'))
this.addOrder()
this.getType()
this.getDevice()
},
methods: {
onConfirm(value, index) {
let p = this.pickData
if(p.ntype == 'device'){
this.orderArr[this.pickData.index].terminalClass = value
}else{
this.orderArr[this.pickData.index].serviceName = value
}
this.pickData.isShow = false
},
onCancel(){
this.pickData.isShow = false
},
addOrder(){
this.orderArr.push({
orderCode: '',
serviceName: '',
terminalClass: '',
deviceNumber: '',
applyId: this.info.applyId
})
},
goSave(){
let arr = this.orderArr
for(let i=0,j=arr.length;i<j;i++){
let p = arr[i]
if(!p.orderCode){
util.toast('请输入工单'+(i+1)+'的工单ID')
return
}
if(p.orderCode.length<=21 || !/^[A-Za-z0-9_]+$/.test(p.orderCode) || !/\d/.test(p.orderCode) || !/_/.test(p.orderCode)){
util.toast('工单ID错误,请复制后直接在此处粘贴')
return
}
if(!p.serviceName){
util.toast('请选择工单'+(i+1)+'的工单类型')
return
}
if(!p.terminalClass){
util.toast('请选择工单'+(i+1)+'的添加设备')
return
}
if(p.terminalClass=='软终端' && !p.deviceNumber){
util.toast('请输入工单'+(i+1)+'的设备串号')
return
}
}
this.confirmFlag = true
},
saveOrder(){
util.httpRequest({
url: '/addDevices',
data: {
data: this.orderArr
},
}).then(res=>{
if(res.code == 200){
util.toast('保存成功')
this.confirmFlag = false
history.go(-1)
//window.location.replace('index.html?time='+new Date().getTime())
}else{
util.toast(res.msg)
}
})
},
pickShow(ntype,index){
this.pickData.ntype = ntype
this.pickData.index = index
this.pickData.title = ntype=='device'?'添加设备':'工单类型'
this.pickData.arr = ntype=='device'?this.deviceArr:this.typeArr
this.pickData.isShow = true
},
getType(){
util.httpRequest({
url: '/listEnum',
middleUrl: '/zhijian-trial/common',
data: {
type: 1
},
}).then(res=>{
if(res.code == 200){
this.deviceArr = res.data.map(item=>{
return item.value
})
}
})
},
getDevice(){
util.httpRequest({
url: '/listEnum',
middleUrl: '/zhijian-trial/common',
data: {
type: 2
},
}).then(res=>{
if(res.code == 200){
this.typeArr = res.data.map(item=>{
return item.value
})
}
})
}
}
})
}
init()
window.vm = vm
})(window.jQuery)
window.addEventListener('load', function () {
document.getElementById('pageDiv').style.display = 'block'; // 显示内容
});
\ No newline at end of file
This diff could not be displayed because it is too large.
const util = new window.publicMethod() ;
const citys = {
'南京市': ['玄武区', '秦淮区', '建邺区', '鼓楼区', '浦口区', '栖霞区', '雨花台区', '江宁区', '六合区', '溧水区', '高淳区'],
'苏州市': ['姑苏区', '吴中区', '相城区', '虎丘区', '吴江区', '新区', '经开区', '昆山市', '常熟市', '张家港市', '太仓市', '苏州工业园区'],
'扬州市': ['广陵区', '邗江区', '江都区', '宝应县', '高邮市', '仪征市'],
'无锡市': ['梁溪区', '锡山区', '惠山区', '滨湖区', '新吴区', '江阴市', '宜兴市'],
'徐州市': ['鼓楼区', '云龙区', '贾汪区', '泉山区', '铜山区', '丰县', '沛县', '睢宁县', '邳州市', '新沂市'],
'常州市': ['天宁区', '钟楼区', '新北区', '武进区', '金坛区', '溧阳市'],
'连云港市': ['海州区', '连云区', '赣榆区', '东海县', '灌云县', '灌南县'],
'淮安市': ['清江浦区', '淮阴区', '淮安区', '洪泽区', '涟水县', '盱眙县', '金湖县'],
'盐城市': ['亭湖区', '盐都区', '盐开区','大丰区', '响水县', '滨海县', '阜宁县', '射阳县', '建湖县','东台市'],
'南通市': ['崇川区', '通州区', '海门区', '如东县', '启东市', '如皋市', '海安市'],
'泰州市': ['海陵区', '高港区', '姜堰区', '兴化市', '靖江市', '泰兴市'],
'宿迁市': ['宿城区', '宿豫区', '沭阳县', '泗阳县', '泗洪县'],
};
new Vue({
el: '#pageDiv',
data: {
tarr: ['精准高效','智能检测','实时监控','全程录像'],
orderFlag: false,
appParam: {},
detail: {},
pickData: {
isShow: false,
title: '地区选择',
arr:[
{
values: Object.keys(citys),
className: 'column1',
defaultIndex: 0
},
{
values: citys['南京市'],
className: 'column2',
defaultIndex: 0
}
],
nCity: '',
nArea: '',
menpai: ''
},
fbData:{
isShow: false,
confirmFlag: false,
explain: '',
},
reasonPickData: {
isShow: false,
title: '原因选择',
orArr: [],
arr:[],
index: 0,
reason: '个人原因'
},
noDataFlag: false
},
created(){
this.getReason()
if(sessionStorage.getItem('huaiAnAppParam')){
this.appParam = JSON.parse(sessionStorage.getItem('huaiAnAppParam'))
this.getDetail()
}else{
this.appParam = JSON.parse(sessionStorage.getItem('listInfoParam'))
this.getDetail('init')
}
},
methods: {
getReason(){
util.httpRequest({
url: '/listEnum',
middleUrl: '/zhijian-trial/common',
data: {
type: 3
},
}).then(res=>{
if(res.code == 200){
this.reasonPickData.orArr = res.data
this.reasonPickData.arr = res.data.map(item=>{
return item.label
})
}
})
},
saveFeedback(){
if(!this.fbData.explain){
util.toast('请填写具体情况')
return
}
let status = ''
let p = this.reasonPickData
p.orArr.forEach(item=>{
if(item.label == p.reason){
status = item.value
}
})
util.httpRequest({
data: {
applyId: this.detail.id,
checkStatus: status,
failReason: this.fbData.explain
},
url: '/unCheck'
}).then(res=>{
if(res.code == 200){
this.getDetail()
this.fbData.isShow = false
this.fbData.confirmFlag = false
util.toast('保存成功')
}else{
util.toast(res.msg)
}
})
},
showCity(){
let __this = this
let cIndex = __this.pickData.nCity?Object.keys(citys).indexOf(__this.pickData.nCity):0
let aIndex = __this.pickData.nArea?(citys[__this.pickData.nCity||'南京市'].indexOf(__this.pickData.nArea)):0
this.pickData.arr = [
{
values: Object.keys(citys),
className: 'column1',
defaultIndex: cIndex
},
{
values: citys[__this.pickData.nCity||'南京市'],
className: 'column2',
defaultIndex: aIndex
}
]
this.pickData.isShow = true
},
onChange(picker, values) {
picker.setColumnValues(1, citys[values[0]]);
},
onConfirm(value, index) {
this.pickData.nCity = value[0]
this.pickData.nArea = value[1]
this.pickData.isShow = false
},
onCancel(){
this.pickData.isShow = false
},
showReason(){
this.reasonPickData.isShow = true
},
reasonCancel(){
this.reasonPickData.isShow = false
},
reasonConfirm(value, index){
this.reasonPickData.reason = value
this.reasonPickData.index = index
this.reasonCancel()
},
release(applyId){
if(!sessionStorage.getItem('haCallId')){
return
}
util.httpRequest({
url: '/releaseConn',
data: {
callId: sessionStorage.getItem('haCallId')||'',
applyId: applyId
}
})
},
getDetail(source){
let json = this.appParam
json.cmcc = source=='init'?true:false
json.phoneModel = navigator.userAgent.toLowerCase()
util.httpRequest({
data: json,
url: '/getOrderInfo'
}).then(res=>{
document.getElementById('pageDiv').style.display = 'block'; // 显示内容
document.getElementById('loading').style.display = 'none'; // 去掉加载框
if(res.code == 200){
this.detail = res.data
let json = {...this.appParam,...{
address: res.data.addressName,
applyId: res.data.id,
campaignId: res.data.campaignId
}}
sessionStorage.setItem('huaiAnAppParam',JSON.stringify(json))
this.release(json.applyId)
}else if(res.code == '5002'){
this.noDataFlag = true
}else{
util.toast(res.msg)
}
})
},
orderError(){
this.orderFlag = true
},
feedback(){
this.fbData.explain = ''
this.reasonPickData.reason = '个人原因'
this.reasonPickData.index = 0
this.fbData.isShow = true
},
closeAlert(){
this.orderFlag = false
},
beginTest(){
if(!this.detail.id){
util.toast('暂未查询到质检信息,请向技术支持方反馈')
return
}
window.location.href = 'demo.html?time='+ new Date().getTime()
},
addOrder(){
this.orderFlag = false
window.location.href = 'addOrder.html?time='+ new Date().getTime()
},
delOrder(index){
util.httpRequest({
data: {
devicesId: this.detail.devicessList[index].id
},
url: '/delDevices'
}).then(res=>{
if(res.code == 200){
util.toast('删除成功')
this.getDetail()
}else{
util.toast(res.msg)
}
})
}
}
})
\ No newline at end of file
window.noShootNum = 5
window.snInputNum = 3
\ No newline at end of file
const util = new window.publicMethod() ;
new Vue({
el: '#app',
data: {
loginInfo: JSON.parse(localStorage.getItem('appLoginInfo') || '{}'),
activeTab: 'tab1',
searchQuery: '',
todoData: [],
completedData: []
},
computed: {
currentData() {
return this.activeTab === 'tab1' ? this.todoData : this.completedData;
},
filteredData() {
if (!this.searchQuery.trim()) {
return this.currentData;
}
let query = this.searchQuery.toLowerCase();
let arr = this.currentData.filter(item =>
item.accNbr.toLowerCase().includes(query)
);
console.log(arr)
return arr;
}
},
methods: {
logout(){
localStorage.removeItem('appLoginInfo');
window.location.replace('login.html');
},
switchTab(tab) {
this.activeTab = tab;
this.searchQuery = ''; // 切换标签时清空搜索
this.queryList()
},
handleItemClick(item) {
sessionStorage.removeItem('huaiAnAppParam')
sessionStorage.setItem('listInfoParam',JSON.stringify(item))
window.location.href = 'index.html'
},
queryList(){
if(this.activeTab==='tab1' && this.todoData.length>0){
return
}
if(this.activeTab==='tab2' && this.completedData.length>0){
return
}
util.httpRequest({
url: '/zj/'+(this.activeTab==='tab1'?'pending':'completed'),
middleUrl: '/zhijian-trial/api',
data: {
campaignId: this.loginInfo.campaignId,
accNbr: this.searchQuery,
},
}).then(res=>{
if(res.code == 200){
if(this.activeTab==='tab1'){
let arr = res.data.records || []
let tArr = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
tArr.forEach(item=>{
arr.push({
accNbr: 'testAccount'+item,
fullAddress: 'test地址'+item,
})
})
this.todoData = arr
}
if(this.activeTab==='tab2'){
this.completedData = res.data.records || []
}
}else{
util.toast(res.msg || '获取失败')
}
})
},
},
mounted() {
this.queryList()
}
});
\ No newline at end of file
const util = new window.publicMethod() ;
new Vue({
el: '#app',
data: {
loginForm: {
employeeId: '',
phoneNumber: '',
verifyCode: ''
},
countdown: 0,
countdownTimer: null,
isLoggedIn: true
},
methods: {
getVerifyCode() {
let pa = this.loginForm
if (!pa.phoneNumber) {
util.toast('请先输入手机号');
return;
}
if (!/^1[3-9]\d{9}$/.test(pa.phoneNumber)) {
util.toast('请输入正确的手机号');
return;
}
// 开始倒计时
this.countdown = 60;
this.countdownTimer = setInterval(() => {
this.countdown--;
if (this.countdown <= 0) {
clearInterval(this.countdownTimer);
}
}, 1000);
util.httpRequest({
url: '/mobile/sendSms',
middleUrl: '/zhijian-trial/api',
data: {
campaignId: pa.employeeId,
phone: pa.phoneNumber,
},
}).then(res=>{
if(res.code == 200){
util.toast('验证码已发送,请注意查收')
}else{
util.toast(res.msg || '获取失败')
}
})
},
login() {
let pa = this.loginForm
// 验证表单
if (!pa.employeeId) {
util.toast('请输入工号');
return;
}
if (!pa.phoneNumber) {
util.toast('请输入手机号');
return;
}
// 验证手机号格式
if (!/^1[3-9]\d{9}$/.test(pa.phoneNumber)) {
util.toast('请输入正确的手机号');
return;
}
if (!pa.verifyCode) {
util.toast('请输入验证码');
return;
}
// 验证验证码格式(假设6位数字)
if (!/^\d{6}$/.test(pa.verifyCode)) {
util.toast('请输入6位验证码');
return;
}
util.httpRequest({
url: '/mobile/login',
middleUrl: '/zhijian-trial/api',
data: {
campaignId: pa.employeeId,
phone: pa.phoneNumber,
smsCode: pa.verifyCode
},
}).then(res=>{
if(res.code == 200){
localStorage.setItem('appLoginInfo', JSON.stringify(res.data))
window.location.href = 'list.html'
}else{
util.toast(res.msg || '登录失败')
}
})
}
},
created(){
let info = localStorage.getItem('appLoginInfo')
if(info){
window.location.href = 'list.html'
}else{
this.isLoggedIn = false
}
},
beforeDestroy() {
// 清除定时器
if (this.countdownTimer) {
clearInterval(this.countdownTimer);
}
}
});
\ No newline at end of file
(function($$) {
"use strict";
let vm
function init() {
vm = new Vue({
el: '#pageDiv',
data: {
info: {}
},
created: function() {
this.info = JSON.parse(sessionStorage.getItem('huaiAnAppParam'))
},
methods: {
goBack(){
history.go(-1)
}
}
})
}
init()
window.vm = vm
})(window.jQuery)
window.addEventListener('load', function () {
document.getElementById('pageDiv').style.display = 'block'; // 显示内容
});
\ No newline at end of file
(function(){
'use strict';
let utils=function(){}
let blackId = ''
let origin = window.location.origin
if(origin.includes('localhost')>0 || origin=='null' || origin.includes('file:')>0){
origin = 'https://testznzl.lgyzpt.com'
}
utils.prototype={
/**
* 获取地址栏后边的参数
*/
getUrlParam:function(m) {
let reg = new RegExp('(^|&)' + m + '=([^&]*)(&|$)')
let r = window.location.href.split('?')
r = r.length === 1 ? null : r[1].match(reg)
if (r == null) return ''
return decodeURIComponent(r[2]).replace(/(#|wechat_redirect|\/[0-9a-zA-Z]*)*/g, '')
},
/**
* 判断设备是Android还是iPhone
*/
androidOrIphone: function () {
var system = window.navigator.userAgent.toLowerCase();
if (system.indexOf("iphone") >= 0 || system.indexOf("ipad") >= 0 || system.indexOf("mac") >= 0 || system.indexOf("ipod") >= 0) {
return false;
}
return true;
},
/**
* 黑框提示
*/
toast: function (str) {
if (document.getElementById("blackDiv")) {
document.getElementById("blackSpan").innerHTML = str;
} else {
var blackDiv = document.createElement("div");
blackDiv.id = "blackDiv";
blackDiv.className = "blackts";
blackDiv.style.position = "fixed";
blackDiv.style.left = "0";
blackDiv.style.bottom = "20%";
blackDiv.style.width = "100%";
blackDiv.style.textAlign = "center";
blackDiv.style.zIndex = "999999";
blackDiv.style.display = 'flex'
blackDiv.style.justifyContent = 'center'
var html = '<div id="blackSpan" style="background: rgba(42,45,50,.94);color: white;';
html += 'border-radius: .1rem;font-size: 0.32rem;padding: .2rem .6rem;max-width: 80%;line-height: 1.5;">';
html += str + '</div>';
blackDiv.innerHTML = html;
document.getElementsByTagName("body")[0].appendChild(blackDiv);
}
if (blackId && blackId != "") {
clearTimeout(blackId);
}
blackId = setTimeout(function () {
if (document.getElementById("blackDiv")) {
document.getElementsByTagName("body")[0].removeChild(document.getElementById("blackDiv"));
}
}, 3000);
},
/**
* zhijian/ha
*
*/
httpRequest:function(param){
let middle = param.middleUrl || '/zhijian-trial/ha'
let pa = localStorage.getItem('appLoginInfo')
if(pa){
pa = JSON.parse(pa)
}else{
pa = {}
}
return new Promise(function(resolve, reject){
axios ({
method: 'post',
url:origin + middle + param.url,
timeout: param.time||15000,
data:param.data,
headers: {
'Content-Type': 'application/json',
'x-access-token': pa.tokenValue
}
}).then((res) => {
resolve(res.data)
}).catch(res => {
reject(res)
})
})
},
}
window.publicMethod = utils
})()
\ No newline at end of file
This diff could not be displayed because it is too large.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>列表页面</title>
<link rel="stylesheet" href="css/list.css">
</head>
<body>
<div id="app" v-cloak>
<div class="list-container">
<div class="tabs">
<div class="left">
<div class="tab-item" :class="{ active: activeTab === 'tab1' }" @click="switchTab('tab1')">待完成</div>
<div class="tab-item" :class="{ active: activeTab === 'tab2' }" @click="switchTab('tab2')">已完成</div>
</div>
<div class="right" @click="logout">退出登录</div>
</div>
<div class="search-section">
<div class="search-box">
<img src="img/4.png" alt="搜索图标" class="search-icon">
<input
type="text"
v-model="searchQuery"
placeholder="查询业务账号"
class="search-input"
>
</div>
</div>
<div class="list-section">
<div class="list-content">
<div
v-for="item in filteredData"
:key="item.id"
class="list-item"
@click="handleItemClick(item)">
<div class="item-content">
<div class="item-row">
<!-- <img src="img/6.png" alt="账号图标" class="item-icon-small"> -->
<div class="item-desc">业务账号:{{ item.accNbr }}</div>
</div>
<div class="item-row">
<!-- <img src="img/5.png" alt="地址图标" class="item-icon-small"> -->
<div class="item-desc">地址:{{ item.fullAddress || '--' }}</div>
</div>
</div>
</div>
<div v-if="filteredData.length === 0" class="empty-state">
<p>暂无数据</p>
</div>
</div>
</div>
</div>
</div>
<script src="js/axios.min.js"></script>
<script src="js/vue.min.js"></script>
<script src="js/util.js"></script>
<script src="js/list.js?1231234"></script>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录页面</title>
<link rel="stylesheet" href="css/login.css">
</head>
<body>
<div id="app" v-cloak>
<div class="login-container" v-if="!isLoggedIn">
<div class="header-section">
<div class="background-image">
<img class="bg" src="img/beijingtu.png" alt="背景图">
<div class="header-content">
<img src="img/logo.png" alt="Logo" class="logo">
<img src="img/hello.png" alt="Logo" class="hello">
<div class="name">欢迎登陆和家智“险”</div>
</div>
</div>
</div>
<div class="login-form">
<div class="input-group">
<img src="img/1.png" alt="工号图标" class="input-icon">
<input
type="text"
v-model="loginForm.employeeId"
placeholder="请输入工号"
class="input-field"
>
</div>
<div class="input-group">
<img src="img/2.png" alt="手机号图标" class="input-icon">
<input
type="tel"
v-model="loginForm.phoneNumber"
placeholder="请输入手机号"
class="input-field"
>
</div>
<div class="input-group">
<img src="img/3.png" alt="验证码图标" class="input-icon">
<input
type="text"
v-model="loginForm.verifyCode"
placeholder="请输入验证码"
class="input-field"
>
<div class="verify-btn" @click="getVerifyCode">{{ countdown > 0 ? countdown + 's' : '获取验证码' }}</div>
</button>
</div>
<button @click="login" class="login-btn">登录</button>
</div>
</div>
</div>
<script src="js/axios.min.js"></script>
<script src="js/vue.min.js"></script>
<script src="js/util.js"></script>
<script src="js/login.js?123123"></script>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>怀化移动</title>
<link rel="stylesheet" href="css/result.css?123123213455">
</head>
<body>
<div id="pageDiv" class="pageDiv">
<div class="infoTop">
<img class="icon" src="https://xpo.oss-cn-beijing.aliyuncs.com/huaian/success.png" alt="">
<div class="status">恭喜您完成质检流程</div>
<div class="detail">
<div class="detli">
<div class="detL">装维ID</div>
<div class="detR">{{info.campaignId}}</div>
</div>
<div class="detli">
<div class="detL">业务账号</div>
<div class="detR">{{info.accNbr}}</div>
</div>
<div class="detli">
<div class="detL">装机地址</div>
<div class="detR">{{info.address}}</div>
</div>
</div>
</div>
<div class="botButt" @click="goBack">返回</div>
</div>
<script src="js/vue.min.js"></script>
<script src="js/result.js?12312312332"></script>
</body>
</html>
\ No newline at end of file
{
"permissions": {
"allow": [
"Bash(npm run build)"
],
"deny": [],
"ask": []
}
}
\ No newline at end of file
const e=""+new URL("employee_tem-BMbgZldQ.xlsx",import.meta.url).href;export{e as default};
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
const e=""+new URL("order_tem-CZcFY6Pk.xlsx",import.meta.url).href;export{e as default};
No preview for this file type
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>视频质检系统</title>
<script type="module" crossorigin src="./assets/index-CYtkjjYo.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-CHzOEySi.css">
</head>
<body>
<div id="app"></div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>视频质检系统</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
\ No newline at end of file
{
"name": "frontend",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"@vitejs/plugin-vue": "^6.0.1",
"element-plus": "^2.11.4",
"vite": "^7.1.9",
"vue": "^3.5.22",
"vue-router": "^4.5.1"
}
}
<template>
<div id="app">
<el-container style="height: 100vh;">
<!-- 侧边栏 -->
<el-aside width="200px" v-if="$route.name !== 'login'">
<el-menu
:default-active="$route.path"
class="el-menu-vertical-demo"
@select="handleSelect"
router
>
<el-menu-item index="/upload">
<el-icon><Upload /></el-icon>
<span>上传工单</span>
</el-menu-item>
<el-menu-item index="/quality-list">
<el-icon><List /></el-icon>
<span>质检信息列表</span>
</el-menu-item>
<el-menu-item index="/staff-list">
<el-icon><User /></el-icon>
<span>工维人员管理</span>
</el-menu-item>
</el-menu>
</el-aside>
<el-container>
<!-- 顶部导航栏 -->
<el-header v-if="$route.name !== 'login'" style="background-color: #fff; border-bottom: 1px solid #dcdfe6; display: flex; justify-content: space-between; align-items: center;">
<div></div>
<el-button type="danger" @click="logout">退出</el-button>
</el-header>
<!-- 主要内容区域 -->
<el-main>
<router-view />
</el-main>
</el-container>
</el-container>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
import { Upload, List, User } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { onMounted } from 'vue'
import {
quitLogin
} from './utils/api'
const router = useRouter()
// 路由守卫
onMounted(() => {
// 检查是否已登录
const token = localStorage.getItem('token')
if (!token && router.currentRoute.value.name !== 'login') {
router.push('/login')
}
})
const handleSelect = (key) => {
console.log(key)
}
const logout = async () => {
const res = await quitLogin()
if (res.code == 200) {
// 登出逻辑
localStorage.removeItem('token')
router.push('/login')
}else{
ElMessage.error(res.msg || '退出登录失败')
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
}
.el-header {
line-height: 60px;
}
.el-aside {
background-color: #fff;
border-right: 1px solid #dcdfe6;
}
</style>
\ No newline at end of file
No preview for this file type
No preview for this file type
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import zhCn from 'element-plus/es/locale/lang/zh-cn'
import 'element-plus/dist/index.css'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(ElementPlus, {
locale: zhCn,
})
app.use(router)
app.mount('#app')
\ No newline at end of file
<template>
<div class="login-container">
<!-- 顶部装饰图标 - 左上角 -->
<div class="top-icons">
<img src="../assets/yd.png" alt="移动" class="top-icon" />
<img src="../assets/cy.png" alt="创益" class="top-icon" />
</div>
<!-- 登录表单 - 靠左 -->
<div class="login-form">
<!-- Logo -->
<div class="logo-section">
<img src="../assets/logo.png" alt="Logo" class="logo" />
</div>
<div class="form-header">
<h2>智能质检运营平台</h2>
</div>
<el-form :model="loginForm" :rules="rules" ref="loginFormRef" class="login-form-inner">
<el-form-item prop="adminNum">
<el-input
v-model="loginForm.adminNum"
placeholder="请输入账号"
prefix-icon="User"
size="large"
class="custom-input"
></el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
type="password"
placeholder="请输入密码"
prefix-icon="Lock"
show-password
size="large"
class="custom-input"
></el-input>
</el-form-item>
<el-form-item prop="captchaCode">
<div class="captcha-wrapper">
<el-input
v-model="loginForm.captchaCode"
placeholder="请输入验证码"
prefix-icon="Key"
size="large"
class="custom-input captcha-input"
></el-input>
<img :src="loginForm.code" @click="getCode" style="height: 45px;widht: 116px;">
</div>
</el-form-item>
<el-form-item style="margin-top: 40px;">
<el-button
type="primary"
size="large"
style="width: 100%; height: 50px; font-size: 16px; border-radius: 25px;"
@click="handleLogin"
:loading="loading"
class="login-btn"
>
登录
</el-button>
</el-form-item>
<el-form-item style="text-align: right;">
<el-button
type="text"
@click="handleForgetPassword"
class="forgot-password"
>
忘记密码?
</el-button>
</el-form-item>
</el-form>
</div>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { login , queryCode} from '../utils/api'
const router = useRouter()
const loginFormRef = ref()
const loading = ref(false)
const currentCaptcha = ref('')
const loginForm = reactive({
adminNum: 'huaihuayidong',
password: 'Hhyd2025..',
captchaCode: '',
code: '',
codeId: ''
})
// 验证码验证函数
const validateCaptcha = (rule, value, callback) => {
if (!value) {
callback(new Error('请输入验证码'))
} else {
callback()
}
}
const rules = {
adminNum: [
{ required: true, message: '请输入账号', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' }
],
captchaCode: [
{ required: true, message: '请输入验证码', trigger: 'blur' },
{ validator: validateCaptcha, trigger: 'blur' }
]
}
const getCode = () => {
queryCode().then(res => {
if (res.code === 200) {
loginForm.code = 'data:image/png;base64,'+res.data.img
loginForm.codeId = res.data.codeId
} else {
ElMessage.error(res.message || '获取验证码失败');
}
}).catch(error => {
ElMessage.error('请求验证码失败: ' + error.message);
});
}
getCode()
const handleLogin = async () => {
if (!loginFormRef.value) return
await loginFormRef.value.validate(async (valid) => {
if (valid) {
loading.value = true
try {
const response = await login({
adminNum: loginForm.adminNum,
password: loginForm.password,
captchaCode: loginForm.captchaCode,
codeId: loginForm.codeId
})
loading.value = false
if (response.code === 200) {
ElMessage.success('登录成功')
// 保存token到localStorage
localStorage.setItem('token', response.data.token)
router.push('/upload')
} else {
ElMessage.error(response.msg || '登录失败')
}
} catch (error) {
loading.value = false
ElMessage.error('登录请求失败: ' + error.message)
}
}
})
}
const handleForgetPassword = () => {
ElMessageBox.alert(`
<div style="text-align: center; padding: 20px;">
<div style="margin-bottom: 15px;">
<img src="/src/assets/suo.png" alt="锁" style="width: 64px; height: 64px;">
</div>
<div style="color: #333; font-size: 16px; font-weight: 500; margin-bottom: 10px;">
忘记密码
</div>
<div style="color: #666; font-size: 14px; line-height: 1.5;">
如需重置密码,请联系系统管理员
</div>
</div>
`, '', {
dangerouslyUseHTMLString: true,
confirmButtonText: '确定',
customClass: 'custom-alert-box'
})
}
</script>
<style>
/* 确保页面没有边距 */
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
</style>
<style scoped>
.login-container {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: url('../assets/bg.png') center/cover no-repeat;
display: flex;
align-items: center;
overflow: hidden;
margin: 0;
padding: 0;
}
.top-icons {
position: absolute;
top: 30px;
left: 30px;
display: flex;
gap: 20px;
z-index: 10;
}
.top-icon {
width: 126px;
object-fit: contain;
}
.login-form {
position: relative;
width: 380px;
margin-left: 80px;
padding: 30px;
background: #ffffff;
border-radius: 8px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
z-index: 10;
animation: slideUp 0.6s ease-out;
}
.logo-section {
text-align: center;
margin-bottom: 20px;
}
.logo {
width: 80px;
height: 80px;
object-fit: contain;
}
.form-header {
text-align: center;
margin-bottom: 30px;
}
.form-header h2 {
color: #333333;
font-size: 20px;
font-weight: 600;
margin: 0;
}
.login-form-inner {
width: 100%;
}
.login-form-inner .el-form-item {
margin-bottom: 20px;
}
.custom-input {
background: #f5f5f5 !important;
border: 1px solid #e0e0e0 !important;
border-radius: 6px !important;
transition: all 0.3s ease !important;
}
.custom-input:hover {
background: #f9f9f9 !important;
border-color: #d0d0d0 !important;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.custom-input:deep(.el-input__wrapper) {
background: transparent !important;
border: none !important;
box-shadow: none !important;
padding: 0 15px;
}
.custom-input:deep(.el-input__inner) {
color: #333;
font-size: 16px;
height: 45px;
}
.custom-input:deep(.el-input__inner::placeholder) {
color: #666;
}
.captcha-wrapper {
display: flex;
gap: 10px;
width: 100%;
align-items: center;
}
.captcha-input {
flex: 1;
}
.login-btn {
background: #0068EE;
border: none !important;
font-weight: 600;
letter-spacing: 1px;
transition: all 0.3s ease !important;
}
.login-btn:hover {
transform: translateY(-2px) !important;
box-shadow: 0 10px 25px rgba(102, 126, 234, 0.4) !important;
}
.login-btn:active {
transform: translateY(0) !important;
}
.forgot-password {
color: #666666 !important;
font-size: 14px;
transition: all 0.3s ease;
}
.forgot-password:hover {
color: #409eff !important;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (max-width: 768px) {
.login-form {
width: 90%;
margin-left: 20px;
padding: 25px 20px;
}
.top-icons {
top: 20px;
left: 20px;
}
.top-icon {
width: 40px;
height: 40px;
}
.logo {
width: 60px;
height: 60px;
}
.form-header h2 {
font-size: 18px;
}
}
</style>
<style>
/* 全局弹框样式 */
.custom-alert-box {
border-radius: 8px !important;
background: #ffffff !important;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15) !important;
border: 1px solid #e0e0e0 !important;
overflow: hidden !important;
max-width: 400px !important;
width: 90% !important;
}
/* 隐藏头部 */
.custom-alert-box .el-message-box__header {
display: none !important;
}
.custom-alert-box .el-message-box__content {
padding: 0 !important;
text-align: center !important;
}
.custom-alert-box .el-message-box__container {
justify-content: center;
}
.custom-alert-box .el-message-box__message {
padding: 30px 20px 20px !important;
color: #333333 !important;
font-size: 14px !important;
line-height: 1.5 !important;
background: #ffffff !important;
display: flex !important;
flex-direction: column !important;
align-items: center !important;
justify-content: center !important;
text-align: center !important;
}
.custom-alert-box .el-message-box__btns {
padding: 0 20px 30px !important;
text-align: center !important;
background: #ffffff !important;
display: flex !important;
justify-content: center !important;
}
.custom-alert-box .el-button {
background: #409eff !important;
border: 1px solid #409eff !important;
border-radius: 4px !important;
padding: 10px 30px !important;
font-size: 14px !important;
font-weight: 400 !important;
color: #ffffff !important;
min-width: 80px !important;
}
.custom-alert-box .el-button:hover {
background: #66b1ff !important;
border-color: #66b1ff !important;
}
.custom-alert-box .el-button:focus {
background: #409eff !important;
border-color: #409eff !important;
}
</style>
\ No newline at end of file
<template>
<div class="quality-list-container">
<el-card>
<template #header>
<div class="card-header">
<span>质检信息列表</span>
</div>
</template>
<div class="filter-section">
<el-row :gutter="20" style="margin-bottom: 20px;">
<el-col :span="5" style="margin-right: 20px;">
<el-date-picker
v-model="filterForm.uploadTime"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
style="width: 100%;"
>
</el-date-picker>
</el-col>
<el-col :span="4">
<el-select
v-model="filterForm.batchStatus"
placeholder="批次状态"
clearable
multiple
style="width: 100%"
>
<el-option v-for="status in pagination.list" :key="status.value" :label="status.label" :value="status.value"></el-option>
</el-select>
</el-col>
<el-col :span="8">
<el-button type="primary" @click="handleFilter">查询</el-button>
<el-button @click="resetFilter">重置</el-button>
</el-col>
</el-row>
</div>
<el-table :data="tableData" :height="tableForm.height" border style="width: 100%">
<el-table-column prop="batchId" label="质检批次ID" width="220"></el-table-column>
<el-table-column prop="orderCount" label="工单数量" width="100"></el-table-column>
<el-table-column prop="userAccountCount" label="用户账号数量" width="120"></el-table-column>
<el-table-column prop="staffCount" label="工维人员数量" width="120"></el-table-column>
<el-table-column prop="createTime" label="上传时间" width="180"></el-table-column>
<el-table-column prop="batchStatus" label="批次状态" width="120">
<template #default="scope">
<el-tag
:type="getTagType(scope.row.batchStatus)"
>
{{ getStatusText(scope.row.batchStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-button
size="small"
type="primary"
@click="viewDetail(scope.row)"
>
查看详情
</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination-container" style="margin-top: 20px; text-align: right;">
<el-pagination
:current-page="pagination.currentPage"
:page-size="pagination.pageSize"
:total="pagination.total"
:page-sizes="pagination.pageSizes"
@sizeChange="handleSizeChange"
layout="total, prev, pager, next, jumper,sizes"
@current-change="handlePageChange"
>
</el-pagination>
</div>
</el-card>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { getQualityBatches , commonListEnum} from '../utils/api'
const router = useRouter()
const filterForm = reactive({
uploadTime: '',
batchStatus: []
})
const pagination = reactive({
currentPage: 1,
pageSize: 20,
pageSizes: [20, 50, 100],
total: 0,
list: []
})
const tableForm = reactive({
height: window.top.document.body.offsetHeight - 346
})
const handleSizeChange = (newSize) => {
pagination.pageSize = newSize;
pagination.currentPage = 1; // 重置到第一页
handleFilter();
};
const tableData = ref([])
const handleFilter = async () => {
try {
const params = {
pageNum: pagination.currentPage,
pageSize: pagination.pageSize,
batchStatusList: filterForm.batchStatus
};
if (filterForm.uploadTime && filterForm.uploadTime.length === 2) {
params.uploadStartTime = filterForm.uploadTime[0];
params.uploadEndTime = filterForm.uploadTime[1];
}
const response = await getQualityBatches(params);
if (response.code === 200) {
tableData.value = response.data.records || [];
pagination.total = response.data.total;
ElMessage.success('查询成功');
} else {
ElMessage.error(response.msg || '查询失败');
}
} catch (error) {
ElMessage.error('查询失败: ' + error.message);
}
}
const resetFilter = () => {
filterForm.uploadTime = '';
filterForm.batchStatus = [];
handleFilter();
}
const getStatusText = (status) => {
let ret = '未知'
pagination.list.forEach(item => {
if(item.value === status) {
ret = item.label
}
})
return ret
}
const getTagType = (status) => {
const typeMap = {
0: 'info',
1: 'warning',
2: 'success'
}
return typeMap[status] || 'info'
}
const viewDetail = (row) => {
sessionStorage.setItem('selectedBatch', JSON.stringify(row))
router.push(`/quality-detail`)
}
const handlePageChange = (page) => {
pagination.currentPage = page;
handleFilter();
}
const queryStatus = async () => {
try {
const response = await commonListEnum({ type: 4});
if (response.code === 200) {
pagination.list = response.data || []
}
} catch (error) {
}
}
onMounted(() => {
// 初始化数据
handleFilter();
queryStatus()
})
</script>
<style scoped>
.quality-list-container {
padding: 20px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
\ No newline at end of file
<template>
<div class="upload-container">
<el-card>
<template #header>
<div class="card-header">
<span>上传工单</span>
</div>
</template>
<div class="upload-section">
<el-upload
class="upload-demo"
drag
:auto-upload="false"
:on-change="handleFileChange"
:before-upload="beforeUpload"
accept=".csv,.xlsx,.xls"
:show-file-list="false"
>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">
将文件拖到此处,或<em>点击上传</em>
</div>
<template #tip>
<div class="el-upload__tip">
请上传CSV或Excel文件,且不超过10MB
</div>
</template>
</el-upload>
<div style="margin-top: 20px; text-align: center;">
<el-button type="primary" @click="handleDownloadTemplate">
下载模板
</el-button>
</div>
</div>
<div class="filter-section" v-if="originalTableData.length > 0">
<el-row :gutter="20" style="margin-bottom: 20px;">
<el-col :span="6">
<el-input
v-model="filterForm.accNbr"
placeholder="业务账号"
></el-input>
</el-col>
<el-col :span="6">
<el-input
v-model="filterForm.campaignIdStr"
placeholder="工维人员工号"
></el-input>
</el-col>
<el-col :span="6">
<el-button type="primary" @click="handleFilter">查询</el-button>
<el-button @click="resetFilter">重置</el-button>
</el-col>
<el-col :span="6" style="text-align: right;">
<el-button type="success" @click="submitData">确定提交</el-button>
</el-col>
</el-row>
<el-table :data="tableData" border style="width: 100%" :row-class-name="tableRowClassName">
<!-- <el-table-column label="状态" width="80" align="center">
<template #default="scope">
<el-icon v-if="scope.row.reason && scope.row.reason.trim() !== ''" color="#f56c6c" size="20">
<Warning />
</el-icon>
<el-icon v-else color="#67c23a" size="20">
<SuccessFilled />
</el-icon>
</template>
</el-table-column> -->
<el-table-column prop="reason" label="错误信息">
<template #default="scope">
<span v-if="scope.row.reason && scope.row.reason.trim() !== ''">
<el-icon color="#f56c6c" style="margin-right: 5px;"><Warning /></el-icon>
{{ scope.row.reason }}
</span>
<span v-else>{{ scope.row.reason }}</span>
</template>
</el-table-column>
<el-table-column prop="campaignId" label="工维人员工号"></el-table-column>
<el-table-column prop="accNbr" label="业务账号"></el-table-column>
<el-table-column prop="orderCode" label="工单号"></el-table-column>
<el-table-column prop="addressName" label="装机地址"></el-table-column>
<el-table-column prop="serviceName" label="工单类型"></el-table-column>
<el-table-column prop="isFttrUser" :formatter="formatFttrUser" label="是否FTTR用户"></el-table-column>
<el-table-column prop="terminalClass" label="设备类型"></el-table-column>
<el-table-column prop="deviceNumber" label="设备串号"></el-table-column>
</el-table>
</div>
</el-card>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { ElMessage } from 'element-plus'
import { Warning, SuccessFilled } from '@element-plus/icons-vue'
import { submitWorkOrders, uploadOrderFile } from '../utils/api'
const tableData = ref([])
const originalTableData = ref([]) // 保存原始数据的副本
const filterForm = reactive({
accNbr: '',
campaignIdStr: ''
})
const formatFttrUser = (row, column, cellValue) => {
if(cellValue === -1){
return ''
}
return cellValue === '1' ? '是' : '否'
}
const beforeUpload = (file) => {
const isLt10M = file.size / 1024 / 1024 < 10
if (!isLt10M) {
ElMessage.error('上传文件大小不能超过 10MB!')
}
return isLt10M
}
const handleFileChange = async (file) => {
const isLt10M = file.size / 1024 / 1024 < 10
if (!isLt10M) {
ElMessage.error('上传文件大小不能超过 10MB!')
return
}
try {
// 使用自定义的uploadOrderFile接口上传文件
const response = await uploadOrderFile(file.raw)
if (response.code === 200) {
ElMessage.success('文件上传成功')
// 使用后端返回的真实数据
const data = response.data.data || []
tableData.value = data
originalTableData.value = [...data] // 保存原始数据副本
} else {
ElMessage.error(response.msg || '文件上传失败')
}
} catch (error) {
ElMessage.error('文件上传失败: ' + error.message)
console.error('Upload error:', error)
}
}
const handleFilter = () => {
// 在前端进行筛选(基于已上传的数据)
if (!filterForm.accNbr && !filterForm.campaignIdStr) {
ElMessage.warning('请输入至少一个筛选条件')
return
}
// 根据筛选条件过滤数据
const filteredData = originalTableData.value.filter(item => {
// 确保字段是字符串类型后再进行匹配
const accNbrStr = item.accNbr != null ? String(item.accNbr) : ''
const campaignIdStr = item.campaignId != null ? String(item.campaignId) : ''
const matchAccNbr = !filterForm.accNbr ||
(accNbrStr && accNbrStr.includes(filterForm.accNbr))
const matchCampaignId = !filterForm.campaignIdStr ||
(campaignIdStr && campaignIdStr.includes(filterForm.campaignIdStr))
return matchAccNbr && matchCampaignId
})
// 更新表格数据
tableData.value = filteredData
ElMessage.success(`筛选完成,共找到 ${filteredData.length} 条记录`)
}
const resetFilter = () => {
// 重置筛选表单
filterForm.accNbr = ''
filterForm.campaignIdStr = ''
// 恢复原始数据
tableData.value = [...originalTableData.value]
ElMessage.info('筛选条件已重置')
}
// 表格行样式类名
const tableRowClassName = ({ row, rowIndex }) => {
// 如果reason有值,则添加错误行样式
if (row.reason && row.reason.trim() !== '') {
return 'error-row'
}
return ''
}
const submitData = async () => {
if (!originalTableData.value || originalTableData.value.length === 0) {
ElMessage.warning('没有数据可提交')
return
}
// 检查是否有错误信息的记录
const hasErrorRecords = originalTableData.value.some(item => item.reason && item.reason.trim() !== '')
if (hasErrorRecords) {
ElMessage.error('信息有误,请修改表格内容后再提交')
return
}
try {
// 调用后端API提交数据
const response = await submitWorkOrders({
orderList: originalTableData.value
})
if (response.code === 200) {
ElMessage.success('数据提交成功')
// 清空表格数据
tableData.value = []
originalTableData.value = []
} else {
ElMessage.error(response.msg || '数据提交失败')
}
} catch (error) {
ElMessage.error('数据提交失败: ' + error.message)
console.error('Submit error:', error)
}
}
const handleDownloadTemplate = async () => {
try {
// 动态导入Excel文件
const module = await import('/src/assets/order_tem.xlsx')
const response = await fetch(module.default)
const blob = await response.blob()
// 创建下载链接
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = '视频质检工单数据模板.xlsx'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(url)
ElMessage.success('模板下载成功')
} catch (error) {
ElMessage.error('模板下载失败: ' + error.message)
}
}
</script>
<style scoped>
.upload-container {
padding: 20px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.upload-section {
margin-bottom: 30px;
}
/* 错误行样式 */
.error-row {
background-color: #fef0f0 !important;
border-left: 3px solid #f56c6c !important;
animation: shake 0.5s ease-in-out;
}
.error-row:hover {
background-color: #fde2e2 !important;
}
/* 错误行中的所有单元格样式 */
.error-row td {
color: #f56c6c !important;
font-weight: 500;
border-color: #f56c6c !important;
}
/* 错误信息列样式 */
.error-row .cell {
font-weight: bold;
color: #f56c6c !important;
}
/* 特别强调错误信息单元格 */
.error-row .el-table_1_column_10 .cell {
font-weight: bold;
text-decoration: underline;
}
/* 抖动动画效果 */
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-2px); }
75% { transform: translateX(2px); }
}
</style>
\ No newline at end of file
import { createRouter, createWebHashHistory } from 'vue-router'
import Login from '../pages/Login.vue'
import Upload from '../pages/Upload.vue'
import QualityList from '../pages/QualityList.vue'
import QualityDetail from '../pages/QualityDetail.vue'
import StaffList from '../pages/StaffList.vue'
const routes = [
{
path: '/',
redirect: '/login'
},
{
path: '/login',
name: 'login',
component: Login
},
{
path: '/upload',
name: 'upload',
component: Upload
},
{
path: '/quality-list',
name: 'quality-list',
component: QualityList
},
{
path: '/quality-detail',
name: 'quality-detail',
component: QualityDetail
},
{
path: '/staff-list',
name: 'staff-list',
component: StaffList
},
]
const router = createRouter({
history: createWebHashHistory('/'),
routes
})
export default router
\ No newline at end of file
// API配置文件
const API_BASE_URL = ''; // 开发环境使用相对路径,通过Vite代理转发
// 获取图形验证码
export const queryCode = () => {
return fetch(`${API_BASE_URL}/zhijian-trial/login/getImgCode`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
}).then(response => response.json());
};
// 登录API
export const login = (params) => {
return fetch(`${API_BASE_URL}/zhijian-trial/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(response => response.json());
};
// 公用枚举
export const commonListEnum = (params) => {
return fetch(`${API_BASE_URL}/zhijian-trial/common/listEnum`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(response => response.json());
};
// 上传文件API
export const uploadOrderFile = (file) => {
const formData = new FormData();
formData.append('file', file);
return fetch(`${API_BASE_URL}/zhijian-trial/zhiJianOrder/importExcel`, {
method: 'POST',
body: formData
}).then(response => response.json());
};
// 获取质检批次列表
export const getQualityBatches = (params) => {
const queryParams = new URLSearchParams(params).toString();
return fetch(`${API_BASE_URL}/zhijian-trial/zhiJianOrder/batchList`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
})
.then(response => response.json());
};
// 获取质检批次详情
export const getQualityBatchDetail = (params) => {
const queryParams = new URLSearchParams(params).toString();
return fetch(`${API_BASE_URL}/zhijian-trial/zhiJianOrder/batchDetail`,{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
})
.then(response => response.json());
};
// 获取此次质检单的设备和工单类型
export const queryOrderAndDevice = (params) => {
return fetch(`${API_BASE_URL}/zhijian-trial/zhiJianOrder/getDevices`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(response => response.json());
};
// 删除工单
export const deleteWorkOrder = (params) => {
return fetch(`${API_BASE_URL}/zhijian-trial/zhiJianOrder/deleteOrder`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(response => response.json());
};
// 新增工单
export const addWorkOrder = (params) => {
return fetch(`${API_BASE_URL}/zhijian-trial/zhiJianOrder/addOrder`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(response => response.json());
};
// 提交工单数据
export const submitWorkOrders = (params) => {
return fetch(`${API_BASE_URL}/zhijian-trial/zhiJianOrder/batchAdd`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(response => response.json());
};
// 获取工维人员列表
export const getStaffList = (params) => {
return fetch(`${API_BASE_URL}/zhijian-trial/userAdmin/list`,{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
})
.then(response => response.json());
};
// 新增工维人员
export const addStaff = (params) => {
return fetch(`${API_BASE_URL}/zhijian-trial/userAdmin/add`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(response => response.json());
};
// 修改工维人员
export const updateStaff = (params) => {
return fetch(`${API_BASE_URL}/zhijian-trial/userAdmin/updateMobile`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(response => response.json());
};
// 删除工维人员
export const deleteStaff = (params) => {
return fetch(`${API_BASE_URL}/zhijian-trial/userAdmin/delete`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(response => response.json());
};
// 批量导入工维人员
export const bulkImportStaff = (file) => {
const formData = new FormData();
formData.append('file', file);
return fetch(`${API_BASE_URL}/zhijian-trial/userAdmin/importExcel`, {
method: 'POST',
body: formData
}).then(response => response.json());
};
// 批量导入工维人员-确认提交
export const submitImportStaff = (params) => {
return fetch(`${API_BASE_URL}/zhijian-trial/userAdmin/batchAdd`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(response => response.json());
};
// 退出登录
export const quitLogin = () => {
return fetch(`${API_BASE_URL}/zhijian-trial/login/loginOut`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
}).then(response => response.json());
};
\ No newline at end of file
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
base: './',
assetsInclude: ['**/*.xlsx', '**/*.xls', '**/*.csv'],
server: {
host: '0.0.0.0',
port: 8080,
proxy: {
'/zhijian-trial': {
target: 'https://testznzl.lgyzpt.com',
changeOrigin: true,
secure: false,
rewrite: (path) => path
}
}
}
})
\ No newline at end of file
npm warn config production Use `--omit=dev` instead.
> frontend@1.0.0 dev
> vite
VITE v7.1.9 ready in 482 ms
➜ Local: http://localhost:8080/
➜ Network: http://192.168.50.138:8080/
17:17:40 [vite] (client) hmr update /src/pages/Upload.vue?vue&type=style&index=0&scoped=ff4aa16f&lang.css
17:17:48 [vite] (client) hmr update /src/pages/Upload.vue?vue&type=style&index=0&scoped=ff4aa16f&lang.css
17:18:16 [vite] (client) hmr update /src/pages/Upload.vue?vue&type=style&index=0&scoped=ff4aa16f&lang.css
17:18:26 [vite] (client) hmr update /src/pages/Upload.vue?vue&type=style&index=0&scoped=ff4aa16f&lang.css
17:19:16 [vite] (client) hmr update /src/pages/Upload.vue?vue&type=style&index=0&scoped=ff4aa16f&lang.css
17:19:28 [vite] (client) hmr update /src/pages/Upload.vue
17:20:05 [vite] (client) hmr update /src/pages/Upload.vue
17:20:54 [vite] (client) hmr update /src/pages/Upload.vue?vue&type=style&index=0&scoped=ff4aa16f&lang.css
17:21:10 [vite] (client) hmr update /src/pages/Upload.vue
17:21:18 [vite] (client) hmr update /src/pages/Upload.vue
17:35:08 [vite] (client) hmr update /src/pages/Login.vue
17:35:14 [vite] (client) hmr update /src/pages/Login.vue?vue&type=style&index=0&scoped=78ff0242&lang.css
17:35:18 [vite] (client) hmr update /src/pages/Login.vue
17:35:29 [vite] (client) hmr update /src/pages/Login.vue
17:52:14 [vite] (client) hmr update /src/pages/Login.vue, /src/pages/QualityList.vue, /src/pages/Upload.vue, /src/pages/QualityDetail.vue
17:52:55 [vite] (client) page reload src/router/index.js
17:54:45 [vite] (client) hmr update /src/App.vue
17:55:04 [vite] (client) hmr update /src/App.vue
18:08:03 [vite] (client) page reload src/router/index.js
18:08:37 [vite] (client) hmr update /src/App.vue
18:09:18 [vite] (client) hmr update /src/App.vue
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!