whyczyk
2021-08-31 46836333f0f884f282e6e628d8ac7f35a3b0402f
初次提交
41个文件已添加
13609 ■■■■■ 已修改文件
.browserslistrc 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.dev 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
babel.config.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
jsconfig.json 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json 11287 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
postcss.config.js 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/favicon.ico 补丁 | 查看 | 原始文档 | blame | 历史
public/index.html 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/App.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/reset.css 237 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/login-ico1.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/login-ico2.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/logo-bg.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/api.js 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/axios.js 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/const_aio.js 372 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/units/function/debounce.js 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/units/function/deepClone.js 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/units/function/deepMerge.js 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/units/function/hidePhone.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/units/function/pageTotal.js 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/units/function/splitString.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/units/function/storage.js 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/units/function/test.js 232 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/units/function/throttle.js 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/units/function/timeFormat.js 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/units/function/timeFrom.js 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/units/function/toThousands.js 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/units/index.js 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/v-upload.vue 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.js 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/alarm-details.vue 210 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/alarm-handle.vue 163 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index.vue 199 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/login.vue 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/routes.js 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/index.js 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vue.config.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.browserslistrc
New file
@@ -0,0 +1,3 @@
> 1%
last 2 versions
not dead
.env.dev
New file
@@ -0,0 +1 @@
NODE_ENV=dev
.gitignore
New file
@@ -0,0 +1,24 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
/.project
babel.config.js
New file
@@ -0,0 +1,5 @@
module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ]
}
jsconfig.json
New file
@@ -0,0 +1,9 @@
{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "exclude": ["node_modules", "dist"]
}
package-lock.json
New file
Diff too large
package.json
New file
@@ -0,0 +1,27 @@
{
  "name": "app-debug",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve --mode dev",
    "build": "vue-cli-service build"
  },
  "dependencies": {
    "axios": "^0.19.2",
    "core-js": "^3.6.5",
    "echarts": "^5.1.1",
    "js-md5": "^0.7.3",
    "vant": "^2.8.1",
    "vue": "^2.6.11",
    "vue-router": "^3.2.0",
    "vuex": "^3.4.0"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-router": "~4.5.0",
    "@vue/cli-plugin-vuex": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "postcss-px-to-viewport": "^1.1.1",
    "vue-template-compiler": "^2.6.11"
  }
}
postcss.config.js
New file
@@ -0,0 +1,29 @@
const path = require('path');
module.exports = ({
    file
}) => {
    const designWidth = file.dirname.includes(path.join('node_modules', 'vant')) ? 375 : 750;
    return {
        plugins: {
            autoprefixer: {},
            "postcss-px-to-viewport": {
                unitToConvert: "px", //需要转换的单位,默认为"px"
                viewportWidth: designWidth, // 视窗的宽度,对应的是我们设计稿的宽度,一般是750
                unitPrecision: 6, // 指定`px`转换为视窗单位值的小数位数
                propList: ["*"],
                viewportUnit: "vw", //指定需要转换成的视窗单位,建议使用vw
                fontViewportUnit: "vw", //字体使用的视口单位
                selectorBlackList: ['.ignore'], // 指定不转换为视窗单位的类,可以自定义,可以无限添加,建议定义一至两个通用的类名
                minPixelValue: 1, // 小于或等于`1px`不转换为视窗单位,你也可以设置为你想要的值
                mediaQuery: true, // 允许在媒体查询中转换`px`
                exclude: [],
                landscape: false, //是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
                landscapeUnit: 'vw', //(String) 横屏时使用的单位
                landscapeWidth: 750, //(Number) 横屏时使用的视口宽度
            }
        }
    }
}
public/favicon.ico
public/index.html
New file
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport"
    content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
  <link rel="icon" href="<%= BASE_URL %>favicon.ico">
  <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
  <noscript>
    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
      Please enable it to continue.</strong>
  </noscript>
  <div id="app"></div>
  <!-- built files will be auto injected -->
</body>
</html>
src/App.vue
New file
@@ -0,0 +1,9 @@
<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>
<style>
  @import "./assets/css/reset.css";
</style>
src/assets/css/reset.css
New file
@@ -0,0 +1,237 @@
@charset "utf-8";
* {
    box-sizing: border-box;
}
html {
    -webkit-text-size-adjust: 100%;
    -ms-text-size-adjust: 100%;
    -webkit-overflow-scrolling: touch;
}
html,
body,
#app {
    width: 100%;
    height: 100%;
}
input[type="submit"],
input[type="reset"],
input[type="button"],
input {
    font-family: Arial, Helvetica, sans-serif;
    resize: none;
    border: none;
}
body,
div,
ul,
li,
ol,
h1,
h2,
h3,
h4,
h5,
h6,
input,
textarea,
select,
p,
dl,
dt,
dd,
a,
img,
button,
form,
table,
th,
tr,
td,
tbody,
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
    font-size: 28px;
    box-sizing: border-box;
}
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
    display: block;
}
img {
    width: 100%;
    height: auto;
    width: auto\9;
    /* ie8 */
    display: block;
    -ms-interpolation-mode: bicubic;
    /*为了照顾ie图片缩放失真*/
}
body,
div,
ul,
li,
ol,
h1,
h2,
h3,
h4,
h5,
h6,
input,
textarea,
select,
p,
dl,
dt,
dd,
a,
img,
button,
form,
table,
th,
tr,
td,
tbody,
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
    margin: 0;
    padding: 0;
}
body {
    font: 24px/1.5 'Microsoft YaHei', '宋体', Tahoma, Arial, sans-serif;
    color: #323233;
    background-color: #fff;
}
em,
i {
    font-style: normal;
}
ul,
li {
    list-style-type: none;
}
strong {
    font-weight: normal;
}
.clearfix:after {
    content: "";
    display: block;
    visibility: hidden;
    height: 0;
    clear: both;
}
.clearfix {
    zoom: 1;
}
a {
    text-decoration: none;
    color: #969696;
    font-family: 'Microsoft YaHei', Tahoma, Arial, sans-serif;
}
a:hover {
    text-decoration: none;
}
ul,
ol {
    list-style: none;
}
h1,
h2,
h3,
h4,
h5,
h6 {
    font-size: 100%;
    font-family: 'Microsoft YaHei';
}
img {
    border: none;
}
input {
    font-family: 'Microsoft YaHei';
}
.one-txt-cut {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
.txt-cut {
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-box-orient: vertical;
}
a:link,
a:active,
a:visited,
a:hover {
    background: none;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
    -webkit-tap-highlight-color: transparent;
}
input[type=button],
input[type=submit],
input[type=file],
button {
    cursor: pointer;
    -webkit-appearance: none;
}
.van-nav-bar .van-icon.van-icon-arrow-left {
    color: #4B88F9 !important;
    font-size: 36px;
    font-weight: bold;
}
src/assets/img/login-ico1.png
src/assets/img/login-ico2.png
src/assets/img/logo-bg.png
src/assets/js/api.js
New file
@@ -0,0 +1,72 @@
import axios from "./axios";
import md5 from "js-md5";
/**
 * 登录系统
 * 参数 "uinf.UName="+用户名+"&uinf.Upassword="+密码+"&uinf.UId="+是否记住密码(0,1)
 * 密码需要使用hex_md5加密
 */
export const login = (username, password) => {
    return axios({
        method: "post",
        url: `LoginAction_login?uinf.UName=${username}&uinf.Upassword=${md5(password)}&uinf.UId=0`,
        data: null
    })
}
/**
 * 获取用户告警列表
 */
export const searchAllByUserId = (data) => {
    return axios({
        method: "post",
        url: `UserWorkAction!searchAllByUserId`,
        data: 'json=' + JSON.stringify(data)
    })
}
/**
 * 开始处理更新状态
 */
export const updateWorkAlarm = (data) => {
    return axios({
        method: "post",
        url: `UserWorkAction!updateWorkAlarm`,
        data: 'json=' + JSON.stringify(data)
    })
}
/**
 * 文件上传
 */
export const uploadAlarmFile = (data) => {
    return axios({
        method: "post",
        url: `MyFileAction!uploadAlarmFile`,
        headers: {
            "Content-Type": "multipart/form-data"
        },
        data: data
    })
}
/**
 * 添加告警处理
 */
export const addUserWork = (data) => {
    return axios({
        method: "post",
        url: `UserWorkAction!addUserWork`,
        data: 'json=' + JSON.stringify(data)
    })
}
/**
 * 查询告警处理详情
 */
export const serchByCondition = (data) => {
    return axios({
        method: "post",
        url: `UserWorkAction!serchByCondition`,
        data: 'json=' + JSON.stringify(data)
    })
}
src/assets/js/axios.js
New file
@@ -0,0 +1,30 @@
import Vue from 'vue';
import axios from 'axios';
if (process.env.NODE_ENV == 'dev') {
    // 跨域请求
    axios.defaults.baseURL = 'http://localhost:8919/fg/';
    axios.defaults.withCredentials = true; // 保持请求头
}
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
}, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    return response;
}, function (error) {
    return Promise.reject(error);
});
Vue.prototype.$axios = axios;
export default axios;
src/assets/js/const_aio.js
New file
@@ -0,0 +1,372 @@
export default {
    // workstates: ["在线浮充","预充电","核容测试","停电放电","内阻测试","K1/D1测试", '离线养护测试', '未知'],
    // alarmstates: ["继电器K1告警","通讯告警","设备过温告警","二极管D1告警"],
    // stopreasons: {
    //     0:'设备掉电',1:'手动终止',2:'放电时间到',3:'放电容量到',4:'单体电压下限到',5:'单体温度上限到',6:'组端电压下限到',
    //     7:'市电中断',8:'单体模块通信异常',9:'存储数据满',10:'机内温度异常',11:'放电电流异常',12:'后台通信中断',13:'内部程序异常',
    //     14:'电源电压高',15:'协议转通信异常',16:'其他',27:'其他设备在工作',28:'其他设备故障停止',29:'电压过高或过低',30:'干接点故障',
    //     31:'单体异常',32:'电压输入过高或过低',33: '电池电流异常', 34:'未知'
    // },
    // failreasons: {
    //     0:'无', 1:'暂停',2:'正在放电测试',3:'正在等待放电',4:'正在限流充电',5:'正在直连充电',6:'正在等待充电',7:'放电时间到停止',
    //     8:'放电容量到停止',9:'单体电压下限到停止',10:'组端电压下限到停止',11:'市电中断停止',12:'存储数据满停止',13:'机内温度异常停止',
    //     14:'放电电流过流停止',15:'后台通信中断停止',16:'负载模块通信中断停止',17:'选择模块通信中断停止',18:'负载模块放电过功率停止',
    //     19:'内部程序异常停止',20:'市电恢复停止升压放电',21:'充电过程中市电中断',22:'组端电压下限',23:'单体温度上限到停止',24:'在线电压异常高停止',
    //     25:'协转通信异常停止',26:'单体通信异常停止',27:'其他设备在工作',28:'其他设备故障停止',29:'电压过高或过低',30:'干接点输入故障',
    //     31:'单体异常',32:'电压输入过高或过低',33: '电池电流异常', 34:'未知'
    // },
    cmd: {
        //-----------------------------启动/停止放电测试命令
        startDisCharge: 0x25,  //启动放电
        // : 0x26;  //启动放电成功
        stopDisCharge: 0x23,  //停止放电
        // : 0x24;  //停止放电成功
        pauseDisCharge: 0x21,  //暂停放电
        // : 0x22;  //暂停放电成功
        // //-----------------------------启动/停止充电测试命令
        startCharge: 0xB1,  //启动充电
        // : 0xB2;  //启动充电成功
        stopCharge: 0xB3,  //停止充电
        // : 0xB4;  //停止充电成功
        pauseCharge: 0xB5,  //暂停充电
        // : 0xB6;  //暂停充电成功
        // //-----------------------------启动活化测试命令
        startActivate: 0xC1,  //启动活化测试
        // : 0xC2;  //启动活化测试成功
        stopActivate: 0xC3,  //停止活化测试
        // : 0xC4;  //停止活化测试成功
        pauseActivate: 0xC5,  //暂停活化测试
        // : 0xC6;  //暂停活化测试成功
        // //-----------------------------清除告警
        clearAlerm: 0xB8,  //清除告警
        // : 0xB9;  //清除告警成功    //------------ FGCD_A059 设备相关命令   ------------------------------------------------------
        // //-----------------------------读取放电参数
        getParams: 0x29,
        // : 0x30;
        // //-----------------------------设置放电参数
        setParams: 0x28
        // : 0x27;
    },
    testType: [
        {
            label: '恒电流',
            value: 0,
        },
        {
            label: '恒功率',
            value: 1
        },
        {
            label: '恒电阻',
            value: 2
        }
    ],
    // 活化开始
    cycleStart: [
        {
            label: '放电',
            value: 0,
        },
        {
            label: '充电',
            value: 1
        }
    ],
    // 放电小时率
    HourRate: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20],
    dischargeRules: {
        //浮充电压(V)
        AutoTestStartVol: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
        },
        //充电容量(AH)
        CharCap: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
        },
        //充电过温
        CharHighTmp: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
        },
        //截止电流
        CharSotpCurr: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
        },
        //充电时长
        CharTimeLong: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
        },
        //放完静置
        CharWaitTime: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 500,
            msg: '取值范围1~500(整数)'
        },
        //充电电流
        ChargeCurrSet: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 100,
            msg: '取值范围1~100(整数)'
        },
        //组端上限
        DCVolHighLimit: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
        },
        //放电容量
        DisCap: {
            pattern: /^[0-9]{1,4}$/,
            regVal: true,
            min: 1,
            max: 2000,
            msg: '取值范围1~2000(整数)'
        },
        // 放电电流
        DisCurr: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
        },
        //预放功率
        DisPower: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
        },
        //放电阻值
        DisPreRes: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
        },
        //放电时长
        DisTime: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 500,
            msg: '取值范围1~500(整数)'
        },
        //充完静置
        DisWaitTime: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 500,
            msg: '取值范围1~500(整数)'
        },
        //浮充时长
        FloatCharTimeLong: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
        },
        //组端下限
        GroupVol_Low: {
            pattern: /^[0-9]+(\.[0-9]{0,1})?$/,
            regVal: true,
            min: 43,
            max: 54,
            msg: '取值范围43.0~54.0'
        },
        //单体上限
        MonVolHightLimit: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
        },
        //单体上限数量
        MonVolHightLimitCount: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 300,
            msg: '取值范围1~300(整数)'
        },
        //单体下限数量
        MonomerLowCount: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 0,
            max: 240,
            msg: '取值范围0~240(整数)'
        },
        //放电过温
        MonomerTmp_High: {
            pattern: /^[0-9]{1,2}(\.[0-9]{0,1})?$/,
            regVal: true,
            min: 10,
            max: 60,
            msg: '取值范围10~60(保留一位小数)'
        },
        //单体下限
        MonomerVol_Low: {
            pattern: /^[0-9]{1,2}(\.[0-9]{0,2})?$/,
            regVal: true,
            min: 1.8,
            max: 2.25,
            msg: '取值范围1.80~2.25(保留两位小数)'
        },
        //活化次数
        OffLineYHTimes: {
            pattern: /^[0-9]{1,2}$/,
            regVal: true,
            min: 1,
            max: 50,
            msg: '取值范围1~50(整数)'
        },
        //充电电压
        OnLineVol_Low: {
            pattern: /^[0-9]{1,3}$/,
            regVal: true,
            min: 1,
            max: 125,
            msg: '取值范围1~125(整数)'
        }
    },
    // stateList: [
    //     {
    //         id: 1,
    //         name: "workState",
    //         type: "",
    //         icon: "",
    //         text: "设备工作状态:",
    //         value: "在线浮充",
    //         show: false
    //     },
    //     {
    //         id: 2,
    //         name: "connect",
    //         type: "",
    //         icon: "el-icon-tongxun",
    //         text: "设备通讯:",
    //         value: "正常",
    //         show: false
    //     },
    //     {
    //         id: 3,
    //         name: "devTemp",
    //         type: "",
    //         icon: "el-icon-wendu",
    //         text: "设备温度:",
    //         value: "正常",
    //         show: false
    //     },
    //     {
    //         id: 4,
    //         name: "contact",
    //         type: "",
    //         icon: "el-icon-fenxiang",
    //         text: "干接点:",
    //         value: "正常",
    //         show: false
    //     },
    //     {
    //         id: 5,
    //         name: "stopReason",
    //         type: "",
    //         icon: "",
    //         text: "核容终止原因:",
    //         value: "未知",
    //         show: false
    //     },
    //     {
    //         id: 6,
    //         name: "failReason",
    //         type: "",
    //         icon: "",
    //         text: "操作失败原因:",
    //         value: "未知",
    //         show: false
    //     },
    //     {
    //         id: 7,
    //         name: "resDay",
    //         type: "",
    //         icon: "",
    //         text: "剩余天数:",
    //         value: "0",
    //         notShow: true,
    //         show: false
    //     },
    //     {
    //         id: 8,
    //         name: "workMode",
    //         type: "",
    //         icon: "",
    //         text: "工作模式:",
    //         value: "停止",
    //         notShow: true,
    //         show: false
    //     },
    //     {
    //         id: 9,
    //         name: "groupVol",
    //         type: "",
    //         icon: "",
    //         text: "组端电压:",
    //         value: "0",
    //         unit: "V",
    //         notShow: true,
    //         show: false
    //     },
    //     {
    //         id: 10,
    //         name: "peakVol",
    //         type: "",
    //         icon: "",
    //         text: "峰值电压:",
    //         value: "0",
    //         unit: "V",
    //         notShow: true,
    //         show: false
    //     }
    // ],
    // getItemByName(name, list) {
    //     let result = false;
    //     for(let i=0; i<list.length; i++) {
    //         let item = list[i];
    //         if(item.name == name) {
    //             result = item;
    //             break;
    //         }
    //     }
    //     return result;
    // }
};
src/assets/units/function/debounce.js
New file
@@ -0,0 +1,29 @@
let timeout = null
/**
 * 防抖原理:一定时间内,只有最后一次操作,再过wait毫秒后才执行函数
 *
 * @param {Function} func 要执行的回调函数
 * @param {Number} wait 延时的时间
 * @param {Boolean} immediate 是否立即执行
 * @return null
 */
function debounce(func, wait = 500, immediate = false) {
  // 清除定时器
  if (timeout !== null) clearTimeout(timeout)
  // 立即执行,此类情况一般用不到
  if (immediate) {
    var callNow = !timeout
    timeout = setTimeout(function() {
      timeout = null
    }, wait)
    if (callNow) typeof func === 'function' && func()
  } else {
    // 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
    timeout = setTimeout(function() {
      typeof func === 'function' && func()
    }, wait)
  }
}
export default debounce
src/assets/units/function/deepClone.js
New file
@@ -0,0 +1,23 @@
// 判断arr是否为一个数组,返回一个bool值
function isArray(arr) {
  return Object.prototype.toString.call(arr) === '[object Array]'
}
// 深度克隆
function deepClone(obj) {
  // 对常见的“非”值,直接返回原来值
  if ([null, undefined, NaN, false].includes(obj)) return obj
  if (typeof obj !== 'object' && typeof obj !== 'function') {
    // 原始类型直接返回
    return obj
  }
  var o = isArray(obj) ? [] : {}
  for (const i in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, i)) {
      o[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i]
    }
  }
  return o
}
export default deepClone
src/assets/units/function/deepMerge.js
New file
@@ -0,0 +1,30 @@
import deepClone from './deepClone'
// JS对象深度合并
function deepMerge(target = {}, source = {}) {
  target = deepClone(target)
  if (typeof target !== 'object' || typeof source !== 'object') return false
  for (var prop in source) {
    if (!Object.prototype.hasOwnProperty.call(source, prop)) continue
    if (prop in target) {
      if (typeof target[prop] !== 'object') {
        target[prop] = source[prop]
      } else {
        if (typeof source[prop] !== 'object') {
          target[prop] = source[prop]
        } else {
          if (target[prop].concat && source[prop].concat) {
            target[prop] = target[prop].concat(source[prop])
          } else {
            target[prop] = deepMerge(target[prop], source[prop])
          }
        }
      }
    } else {
      target[prop] = source[prop]
    }
  }
  return target
}
export default deepMerge
src/assets/units/function/hidePhone.js
New file
@@ -0,0 +1,5 @@
function hidePhone(tel) {
    var reg = /^(\d{3})\d{4}(\d{4})$/;
    return tel.replace(reg, "$1****$2");
}
export default hidePhone
src/assets/units/function/pageTotal.js
New file
@@ -0,0 +1,16 @@
/*
  根据总数计算总页数
  "总条数":rowCount,"每页总条数":pageSize
*/
function pageTotal(rowCount, pageSize) {
  if (rowCount == null || rowCount == "") {
    return 0;
  } else {
    if (pageSize != 0 && rowCount % pageSize == 0) {
      return parseInt(rowCount / pageSize)
    } else if (pageSize != 0 && rowCount % pageSize != 0) {
      return parseInt(rowCount / pageSize) + 1;
    }
  }
}
export default pageTotal
src/assets/units/function/splitString.js
New file
@@ -0,0 +1,5 @@
function splitString(str) {
    if (str.length == 0) return []
    else return str.split(',')
}
export default splitString
src/assets/units/function/storage.js
New file
@@ -0,0 +1,21 @@
function setStorage(key, value) {
    uni.setStorage({
        key: key,
        data: value,
    })
}
function getStorage(key) {
    try {
        const value = uni.getStorageSync(key)
        if (value)
            return value
    } catch (e) {
        console.log(e)
    }
}
export default {
    setStorage,
    getStorage
}
src/assets/units/function/test.js
New file
@@ -0,0 +1,232 @@
/**
 * 验证电子邮箱格式
 */
function email(value) {
  return /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/.test(value);
}
/**
 * 验证手机格式
 */
function mobile(value) {
  return /^1[23456789]\d{9}$/.test(value)
}
/**
 * 验证URL格式
 */
function url(value) {
  return /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-.\/?%&=]*)?/.test(value)
}
/**
 * 验证日期格式
 */
function date(value) {
  return !/Invalid|NaN/.test(new Date(value).toString())
}
/**
 * 验证ISO类型的日期格式
 */
function dateISO(value) {
  return /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value)
}
/**
 * 验证十进制数字
 */
function number(value) {
  return /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value)
}
/**
 * 验证整数
 */
function digits(value) {
  return /^\d+$/.test(value)
}
/**
 * 验证身份证号码
 */
function idCard(value) {
  return /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
    value)
}
/**
 * 是否车牌号
 */
function carNo(value) {
  // 新能源车牌
  const xreg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))/;
  // 旧车牌
  const creg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/;
  if (value.length === 7) {
    return creg.test(value);
  } else if (value.length === 8) {
    return xreg.test(value);
  } else {
    return false;
  }
}
/**
 * 金额,只允许2位小数
 */
function amount(value) {
  //金额,只允许保留两位小数
  return /^[1-9]\d*(,\d{3})*(\.\d{1,2})?$|^0\.\d{1,2}$/.test(value);
}
/**
 * 中文
 */
function chinese(value) {
  let reg = /^[\u4e00-\u9fa5]+$/gi;
  return reg.test(value);
}
/**
 * 只能输入字母
 */
function letter(value) {
  return /^[a-zA-Z]*$/.test(value);
}
/**
 * 只能是字母或者数字
 */
function enOrNum(value) {
  //英文或者数字
  let reg = /^[0-9a-zA-Z]*$/g;
  return reg.test(value);
}
/**
 * 验证是否包含某个值
 */
function contains(value, param) {
  return value.indexOf(param) >= 0
}
/**
 * 验证一个值范围[min, max]
 */
function range(value, param) {
  return value >= param[0] && value <= param[1]
}
/**
 * 验证一个长度范围[min, max]
 */
function rangeLength(value, param) {
  return value.length >= param[0] && value.length <= param[1]
}
/**
 * 是否固定电话
 */
function landline(value) {
  let reg = /^\d{3,4}-\d{7,8}(-\d{3,4})?$/;
  return reg.test(value);
}
/**
 * 判断是否为空
 */
function empty(value) {
  switch (typeof value) {
    case 'undefined':
      return true;
    case 'string':
      if (value.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true;
      break;
    case 'boolean':
      if (!value) return true;
      break;
    case 'number':
      if (0 === value || isNaN(value)) return true;
      break;
    case 'object':
      if (null === value || value.length === 0) return true;
      for (var i in value) {
        return false;
      }
      return true;
  }
  return false;
}
/**
 * 是否json字符串
 */
function jsonString(value) {
  if (typeof value == 'string') {
    try {
      var obj = JSON.parse(value);
      if (typeof obj == 'object' && obj) {
        return true;
      } else {
        return false;
      }
    } catch (e) {
      return false;
    }
  }
  return false;
}
/**
 * 是否数组
 */
function array(value) {
  if (typeof Array.isArray === "function") {
    return Array.isArray(value);
  } else {
    return Object.prototype.toString.call(value) === "[object Array]";
  }
}
/**
 * 是否对象
 */
function object(value) {
  return Object.prototype.toString.call(value) === '[object Object]';
}
/**
 * 是否短信验证码
 */
function code(value, len = 6) {
  return new RegExp(`^\\d{${len}}$`).test(value);
}
export default {
  email,
  mobile,
  url,
  date,
  dateISO,
  number,
  digits,
  idCard,
  carNo,
  amount,
  chinese,
  letter,
  enOrNum,
  contains,
  range,
  rangeLength,
  empty,
  isEmpty: empty,
  jsonString,
  landline,
  object,
  array,
  code
}
src/assets/units/function/throttle.js
New file
@@ -0,0 +1,31 @@
let flag
/**
 * 节流原理:在一定时间内,只能触发一次
 *
 * @param {Function} func 要执行的回调函数
 * @param {Number} wait 延时的时间
 * @param {Boolean} immediate 是否立即执行
 * @return null
 */
function throttle(func, wait = 500, immediate = true) {
  if (immediate) {
    if (!flag) {
      flag = true
      // 如果是立即执行,则在wait毫秒内开始时执行
      typeof func === 'function' && func()
      setTimeout(() => {
        flag = false
      }, wait)
    }
  } else {
    if (!flag) {
      flag = true
      // 如果是非立即执行,则在wait毫秒内的结束处执行
      setTimeout(() => {
        flag = false
        typeof func === 'function' && func()
      }, wait)
    }
  }
}
export default throttle
src/assets/units/function/timeFormat.js
New file
@@ -0,0 +1,34 @@
/**
 * 该函数必须传入第一个参数,第二个参数是可选的,函数返回一个格式化好的时间。
   time <String> 任何合法的时间格式、秒或毫秒的时间戳
   format <String> 时间格式,可选。默认为yyyy-mm-dd,年为"yyyy",月为"mm",日为"dd",时为"hh",分为"MM",秒为"ss",格式可以自由搭配,如: yyyy:mm:dd,yyyy-mm-dd,yyyy年mm月dd日,yyyy年mm月dd日 hh时MM分ss秒,yyyy/mm/dd/,MM:ss等组合
 */
function timeFormat(timestamp = null, fmt = 'yyyy-mm-dd') {
  // 其他更多是格式化有如下:
  // yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合
  timestamp = parseInt(timestamp)
  // 如果为null,则格式化当前时间
  if (!timestamp) timestamp = Number(new Date())
  // 判断用户输入的时间戳是秒还是毫秒,一般前端js获取的时间戳是毫秒(13位),后端传过来的为秒(10位)
  if (timestamp.toString().length === 10) timestamp *= 1000
  const date = new Date(timestamp)
  let ret
  const opt = {
    'y+': date.getFullYear().toString(), // 年
    'm+': (date.getMonth() + 1).toString(), // 月
    'd+': date.getDate().toString(), // 日
    'h+': date.getHours().toString(), // 时
    'M+': date.getMinutes().toString(), // 分
    's+': date.getSeconds().toString() // 秒
    // 有其他格式化字符需求可以继续添加,必须转化成字符串
  }
  for (const k in opt) {
    ret = new RegExp('(' + k + ')').exec(fmt)
    if (ret) {
      fmt = fmt.replace(ret[1], ret[1].length === 1 ? opt[k] : opt[k].padStart(ret[1].length, '0'))
    }
  }
  return fmt
}
export default timeFormat
src/assets/units/function/timeFrom.js
New file
@@ -0,0 +1,46 @@
import timeFormat from './timeFormat'
/**
 * 时间戳转为多久之前
 * @param String timestamp 时间戳
 * @param String | Boolean format 如果为时间格式字符串,超出一定时间范围,返回固定的时间格式;
 * 如果为布尔值false,无论什么时间,都返回多久以前的格式
 */
function timeFrom(timestamp = null, format = 'yyyy-mm-dd') {
  if (timestamp == null) timestamp = Number(new Date())
  timestamp = parseInt(timestamp)
  // 判断用户输入的时间戳是秒还是毫秒,一般前端js获取的时间戳是毫秒(13位),后端传过来的为秒(10位)
  if (timestamp.toString().length === 10) timestamp *= 1000
  var timer = new Date().getTime() - timestamp
  timer = parseInt(timer / 1000)
  // 如果小于5分钟,则返回"刚刚",其他以此类推
  let tips = ''
  switch (true) {
    case timer < 300:
      tips = '刚刚'
      break
    case timer >= 300 && timer < 3600:
      tips = parseInt(timer / 60) + '分钟前'
      break
    case timer >= 3600 && timer < 86400:
      tips = parseInt(timer / 3600) + '小时前'
      break
    case timer >= 86400 && timer < 2592000:
      tips = parseInt(timer / 86400) + '天前'
      break
    default:
      // 如果format为false,则无论什么时间戳,都显示xx之前
      if (format === false) {
        if (timer >= 2592000 && timer < 365 * 86400) {
          tips = parseInt(timer / (86400 * 30)) + '个月前'
        } else {
          tips = parseInt(timer / (86400 * 365)) + '年前'
        }
      } else {
        tips = timeFormat(timestamp, format)
      }
  }
  return tips
}
export default timeFrom
src/assets/units/function/toThousands.js
New file
@@ -0,0 +1,16 @@
/**
 * 数字添加千分位
 */
function toThousands(num) {
    var num = (num || 0).toString(),
        result = '';
    while (num.length > 3) {
        result = ',' + num.slice(-3) + result;
        num = num.slice(0, num.length - 3);
    }
    if (num) {
        result = num + result;
    }
    return result;
}
export default toThousands
src/assets/units/index.js
New file
@@ -0,0 +1,46 @@
// 深度克隆
import deepClone from './function/deepClone'
// 对象合并
import deepMerge from './function/deepMerge'
// 时间格式化
import timeFormat from './function/timeFormat'
// 时间戳格式化,返回多久之前
import timeFrom from './function/timeFrom'
// 规则检验
import test from './function/test'
// 防抖
import debounce from './function/debounce'
// 节流
import throttle from './function/throttle.js'
//隐藏部分手机号
import hidePhone from './function/hidePhone'
//,号分割字符串
import splitString from './function/splitString'
//数字添加千分位
import toThousands from './function/toThousands'
//计算总页数
import pageTotal from './function/pageTotal'
export default {
    deepClone,
    deepMerge,
    timeFormat,
    timeFrom,
    debounce,
    throttle,
    test,
    hidePhone,
    splitString,
    toThousands,
    pageTotal,
}
src/components/v-upload.vue
New file
@@ -0,0 +1,98 @@
<template>
  <van-uploader :after-read="afterRead" v-model="getFileList" accept="image/png, image/jpeg"
    :max-size="10 * 1024 * 1024" @oversize="oversize" :disabled="disabled" />
</template>
<script>
  import {
    uploadAlarmFile
  } from '@/assets/js/api'
  export default {
    name: "v-upload",
    props: {
      value: {
        type: String,
        default: ""
      },
      disabled: {
        type: Boolean,
        default: false
      },
      afterOrBefore: {
        type: String,
        default: 'before'
      }
    },
    data() {
      return {
        fileList: this.value
      }
    },
    model: {
      prop: "value",
      event: "valChange"
    },
    watch: {
      value(newValue) {
        this.fileList = newValue;
      },
      fileList(newValue) {
        this.$emit("valChange", newValue);
      }
    },
    computed: {
      getFileList: {
        get() {
          if (this.fileList) {
            return this.fileList.split(",").map(item => {
              return {
                url: item
              };
            });
          }
          return [];
        },
        set(newValue) {
          var fileList = [];
          newValue.forEach(item => {
            if (item.url) {
              fileList.push(item.url);
            }
          });
          this.fileList = fileList.join(",");
        }
      }
    },
    methods: {
      // 上传图片
      afterRead(file) {
        var formData = new FormData();
        let json = JSON.stringify({
          afterOrBefore: this.afterOrBefore
        })
        formData.append("file", file.file);
        formData.append("json", json);
        //上传图片接口
        uploadAlarmFile(formData).then(res => {
          let resData = JSON.parse(res.data.result);
          if (resData.code == 1) {
            if (this.fileList) {
              var arr = this.fileList.split(",");
              arr.push(resData.data[0]);
              this.fileList = arr.join(",");
              return false;
            }
            this.fileList = resData.data[0];
          }
        });
      },
      // 文件过大
      oversize(e) {
        this.$toast.fail("图片过大!");
      }
    }
  }
</script>
<style scoped>
</style>
src/main.js
New file
@@ -0,0 +1,66 @@
import Vue from 'vue'
import axios from './assets/js/axios'
import {
  Toast,
  Notify,
  Dialog,
  Tabbar,
  TabbarItem,
  CellGroup,
  Cell,
  Icon,
  Button,
  NavBar,
  Grid,
  GridItem,
  Row,
  Col,
  Collapse,
  CollapseItem,
  Steps,
  Step,
  Divider,
  Switch,
  Tag,
  Search,
  Field,
  Uploader,
  Popup,
  CheckboxGroup,
  Checkbox,
  PullRefresh,
  ActionSheet,
  List,
  Tab,
  Tabs,
  Image,
  Form,
  Picker,
  Empty,
} from 'vant';
import App from './App.vue'
import router from './router'
import store from './store'
import 'vant/lib/index.css'; // 全局引入样式
import units from './assets/units'
Vue.config.productionTip = false
Vue.use(Toast).use(Notify).use(Picker).use(Form).use(Image).use(Dialog).use(Tabbar).use(TabbarItem).use(CellGroup).use(Cell).use(Icon).use(Button).use(NavBar).use(Grid).use(GridItem).use(Row).use(Col).use(Collapse).use(CollapseItem).use(Steps).use(Step).use(Divider).use(Switch).use(Tag).use(Search).use(Field).use(Uploader).use(Popup).use(CheckboxGroup).use(Checkbox).use(PullRefresh).use(ActionSheet).use(List).use(Tab).use(Tabs).use(Empty);
Vue.prototype.$notify = Notify;
Vue.prototype.$dialog = Dialog;
Vue.prototype.$toast = Toast;
Vue.prototype.$axios = axios;
Vue.prototype.$units = units;
new Vue({
  router,
  store,
  render: function (h) {
    return h(App)
  }
}).$mount('#app')
src/pages/alarm-details.vue
New file
@@ -0,0 +1,210 @@
<template>
  <div class="alarm-details">
    <van-nav-bar title="告警详情" @click-left="$router.back()" left-arrow fixed safe-area-inset-top placeholder>
    </van-nav-bar>
    <div class="detailsCon">
      <div class="card">
        <div class="commonTitle cardTitle">
          {{alarmInfo.alarmData.alarmname}}
        </div>
        <div class="commonTitle">
          <div class="label">
            站点名称:
          </div>
          <div class="text">
            {{alarmInfo.alarmData.stationname}}
          </div>
        </div>
        <div class="commonTitle">
          <div class="label">
            电池组:
          </div>
          <div class="text">
            {{alarmInfo.alarmData.battGroupName}}
          </div>
        </div>
        <div class="commonTitle">
          <div class="label">
            告警等级:
          </div>
          <div class="text">
            {{alarmInfo.alarmData.alarmtype}}
          </div>
        </div>
        <div class="commonTitle">
          <div class="label">
            告警时间:
          </div>
          <div class="text">
            {{alarmInfo.alarmData.alm_start_time}}
          </div>
        </div>
        <div class="commonTitle">
          <div class="label">
            确认时间:
          </div>
          <div class="text">
            {{alarmInfo.alarmData.alm_confirmed_time}}
          </div>
        </div>
        <div class="commonTitle">
          <div class="label">
            告警值:
          </div>{{alarmInfo.alarmData.alm_value}}
        </div>
        <div class="commonTitle">
          <div class="label">
            处理状态:
          </div>
          <div class="text" v-if="alarmInfo.status==2">
            处理中
          </div>
          <div class="text" v-else-if="alarmInfo.status==3">
            已处理
          </div>
          <div class="text" v-else>
            待处理
          </div>
        </div>
      </div>
      <div class="subBtn" @click="startHandle" v-if="alarmInfo.status==1">开始处理</div>
      <div class="card" v-if="alarmInfo.status==2">
        <van-steps :active="stepsActive">
          <van-step>处理中</van-step>
          <van-step>待审核</van-step>
          <van-step>已完成</van-step>
        </van-steps>
      </div>
      <div class="subBtn" @click="toPage('edit')" v-if="alarmInfo.status==2">继续处理</div>
    </div>
  </div>
</template>
<script>
  import {
    updateWorkAlarm
  } from '@/assets/js/api'
  export default {
    data() {
      return {
        stepsActive: 0,
        alarmInfo: {
          id: 0,
          alarmRecId: 0,
          battGroupId: 0,
          managerId: 0,
          status: 0,
          dispatchTime: "",
          alarmData: {
            num: 0,
            BattGroupId: 0,
            MonNum: 0,
            alm_signal_id: 0,
            alm_level: 0,
            alm_start_time: "",
            alm_end_time: "",
            alm_value: 0,
            alm_is_confirmed: 0,
            alm_confirmed_time: "",
            stationname: "",
            battGroupName: "",
            alarmname: "",
            alarmtype: ""
          }
        }
      }
    },
    mounted() {
      this.alarmInfo = JSON.parse(this.$route.query.alarmData);
    },
    methods: {
      toPage(type) {
        this.$router.push({
          path: '/alarmHandle',
          query: {
            id: this.alarmInfo.id,
            type: type
          }
        })
      },
      //开始处理
      startHandle() {
        let postData = this.$units.deepClone(this.alarmInfo)
        postData.status = 2;
        postData.userId = sessionStorage.getItem('userId');
        updateWorkAlarm(postData).then((res) => {
          let resData = JSON.parse(res.data.result)
          if (resData.code == 1) {
            this.toPage('add')
          }
        }).catch((err) => {
          console.log(err)
        });
      }
    }
  }
</script>
<style scoped>
  .alarm-details {
    width: 100%;
    height: 100%;
    background: #F5F5F5;
  }
  .detailsCon {
    padding: 24px;
  }
  .card {
    background-color: #FFFFFF;
    border-radius: 16px;
    margin: 0 auto 24px;
    width: 702px;
    padding: 24px;
    box-shadow: 0px 4px 20px 0px rgba(75, 136, 249, 0.2);
  }
  .commonTitle {
    font-size: 28px;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: #333333;
    line-height: 40px;
    padding-bottom: 24px;
    border-bottom: 1px solid #EEEEEE;
    margin-bottom: 22px;
    display: flex;
    align-items: center;
  }
  .cardTitle {
    font-weight: bold;
  }
  .commonTitle .label {
    line-height: 40px;
    display: inline-block;
    width: 150px;
  }
  .commonTitle .text {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .subBtn {
    width: 702px;
    height: 98px;
    background: #4B88F9;
    border-radius: 8px;
    display: flex;
    justify-content: center;
    align-items: center;
    color: #FFFFFF;
    font-size: 36px;
    margin-top: 48px;
  }
</style>
src/pages/alarm-handle.vue
New file
@@ -0,0 +1,163 @@
<template>
  <div class="alarm-handle">
    <van-nav-bar title="告警处理" @click-left="$router.back()" left-arrow fixed safe-area-inset-top placeholder>
    </van-nav-bar>
    <div class="handleCon">
      <div class="textareaCon">
        <van-field v-model="alarmInfo.describe" rows="2" autosize label="告警描述" type="textarea" placeholder="请输入告警描述…"
          show-word-limit />
        <v-upload :value="alarmInfo.imageBefore" @valChange="beforeUploadChange" afterOrBefore="before" class="upload">
        </v-upload>
      </div>
      <div class="textareaCon">
        <van-field v-model="alarmInfo.workWay" rows="2" autosize label="处理方法" type="textarea" placeholder="请输入处理方法…"
          show-word-limit />
        <v-upload :value="alarmInfo.imageAfter" @valChange="afterUploadChange" afterOrBefore="after" class="upload">
        </v-upload>
      </div>
      <div class="textareaCon">
        <van-field v-model="alarmInfo.workSuggest" rows="2" autosize label="意见建议" type="textarea" placeholder="请输入意见建议…"
          show-word-limit />
      </div>
      <div class="btnCon">
        <div class="subBtn" @click="submit">保存</div>
        <div class="subBtn">提交</div>
      </div>
    </div>
  </div>
</template>
<script>
  import vUpload from '@/components/v-upload.vue'
  import {
    addUserWork,
    serchByCondition
  } from '@/assets/js/api'
  export default {
    components: {
      vUpload
    },
    data() {
      return {
        alarmInfo: {
          checkStatus: 0,
          createTime: "",
          endTime: "",
          imageAfter: "",
          imageBefore: "",
          managerId: 0,
          note: "",
          userId: 0,
          workId: 0,
          workSuggest: "",
          workWay: "",
        }
      }
    },
    mounted() {
      this.alarmInfo.workId = this.$route.query.id;
      let type = this.$route.query.type;
      if (type == 'edit') {
        this.loadHandle()
      }
    },
    methods: {
      beforeUploadChange(list) {
        this.alarmInfo.imageBefore = list
      },
      afterUploadChange(list) {
        this.alarmInfo.imageAfter = list
      },
      //查询告警处理详情
      loadHandle() {
        let postData = {
          workId: this.alarmInfo.workId
        }
        serchByCondition(postData).then((res) => {
          let resData = JSON.parse(res.data.result)
          console.log(resData)
          if (resData.code == 1) {
            this.alarmInfo = resData.data[resData.data.length - 1]
          }
        }).catch((err) => {
          console.log(err)
        });
      },
      //保存提交
      submit() {
        addUserWork(this.alarmInfo).then((res) => {
          let resData = JSON.parse(res.data.result)
          if (resData.code == 1) {
            this.$toast(resData.msg)
          }
        }).catch((err) => {
          console.log(err)
        });
      }
    }
  }
</script>
<style scoped>
  .alarm-handle {
    width: 100%;
    min-height: 100%;
    background: #F5F5F5;
  }
  .handleCon {
    padding: 24px;
  }
  .handleTitle {
    font-size: 28px;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    color: #333333;
  }
  .textareaCon {
    background: #FFFFFF;
    border-radius: 16px;
    padding: 24px;
    box-shadow: 0px 4px 20px 0px rgba(75, 136, 249, 0.2);
    margin-bottom: 24px;
  }
  .textareaCon /deep/ .van-cell {
    padding: 20px 0;
  }
  .textareaCon /deep/ .van-cell::after {
    display: none;
  }
  .upload {
    margin-top: 16px;
  }
  .btnCon {
    width: 100%;
    display: flex;
    align-items: center;
  }
  .btnCon .subBtn {
    flex: 1;
    height: 98px;
    background: #07c160;
    border-radius: 8px;
    display: flex;
    justify-content: center;
    align-items: center;
    color: #FFFFFF;
    font-size: 36px;
    margin-top: 48px;
    margin-right: 24px;
  }
  .btnCon .subBtn:last-of-type {
    margin-right: 0;
    background: #4B88F9;
  }
</style>
src/pages/index.vue
New file
@@ -0,0 +1,199 @@
<template>
  <div class="indexWarp">
    <van-nav-bar title="告警列表" fixed safe-area-inset-top placeholder></van-nav-bar>
    <van-tabs v-model="active" color="#4B88F9" animated swipeable background="#ffffff">
      <van-tab :title="tab.title" v-for="(tab,i) in tabs1" :key="i">
        <van-pull-refresh v-model="tab.refreshing" @refresh="onRefresh(tab)">
          <van-list v-model="tab.loading" :finished="tab.finished" finished-text="没有更多了" @load="loadData(tab)">
            <div class="pd-24">
              <div class="listWarp">
                <van-cell center is-link v-for="(item,i) in tab.listData" :key="i" @click="toPage(item)">
                  <template #title>
                    <div class="alarmTitle">
                      <van-tag class="tag" v-if="item.alarmData.alm_level==1">一级</van-tag>
                      <van-tag class="tag" v-else-if="item.alarmData.alm_level==2">二级</van-tag>
                      <van-tag class="tag" v-else-if="item.alarmData.alm_level==3">三级</van-tag>
                      {{item.alarmData.alarmname}}
                    </div>
                    <div class="time">{{item.dispatchTime}}</div>
                  </template>
                </van-cell>
              </div>
            </div>
          </van-list>
        </van-pull-refresh>
      </van-tab>
    </van-tabs>
  </div>
</template>
<script>
  import {
    searchAllByUserId
  } from '@/assets/js/api'
  export default {
    components: {},
    data() {
      return {
        active: 0,
        tabs1: [{
          title: '全部',
          listData: [],
          loading: false,
          finished: false,
          refreshing: false,
          page: {
            pageSize: 6,
            pageCurr: 0
          }
        }, {
          title: '待处理',
          listData: [],
          loading: false,
          finished: false,
          refreshing: false,
          page: {
            pageSize: 6,
            pageCurr: 0
          }
        }, {
          title: '处理中',
          listData: [],
          loading: false,
          finished: false,
          refreshing: false,
          page: {
            pageSize: 6,
            pageCurr: 0
          }
        }, {
          title: '已处理',
          listData: [],
          loading: false,
          finished: false,
          refreshing: false,
          page: {
            pageSize: 6,
            pageCurr: 0
          }
        }],
      }
    },
    mounted() {
      this.loadData(this.tabs1[0])
    },
    methods: {
      loadData(tab) {
        // 将 loading 设置为 true,表示处于加载状态
        tab.loading = true;
        tab.page.pageCurr++
        let status = null
        if (this.active == 0) {
          status = null
        } else {
          status = this.active
        }
        let postData = {
          status: status,
          page: tab.page
        }
        searchAllByUserId(postData).then((res) => {
          let resData = JSON.parse(res.data.result).data
          tab.loading = false;
          console.log(resData)
          if (resData && resData.data && resData.data.length > 0) {
            tab.listData.push(...resData.data)
          }
          if (resData.pageCurr >= this.$units.pageTotal(resData.pageAll, tab.page.pageSize)) {
            tab.finished = true;
          } else {
            tab.finished = false;
          }
        }).catch((err) => {
          tab.loading = false;
          console.log(err)
        });
      },
      onRefresh(tab) {
        // 清空列表数据
        tab.finished = false;
        tab.listData = [];
        tab.refreshing = false;
        tab.page = {
          pageSize: 6,
          pageCurr: 0
        }
        // 重新加载数据
        this.loadData(tab);
      },
      toPage(item) {
        this.$router.push({
          path: '/alarmDetails',
          query: {
            alarmData: JSON.stringify(item)
          }
        })
      },
    }
  }
</script>
<style scoped>
  .indexWarp {
    width: 100%;
    height: 100%;
    background: #F5F5F5;
  }
  .van-tabs {
    height: calc(100% - 92px);
    padding-top: 92px;
  }
  .van-tabs /deep/ .van-tabs__content {
    min-height: 100%;
  }
  .van-tabs /deep/ .van-tabs__wrap {
    position: fixed;
    left: 0;
    width: 100%;
    top: 92px;
    z-index: 9;
    border-bottom: 1px solid #ededed;
  }
  .pd-24 {
    padding: 24px;
  }
  .listWarp {
    background: #FFFFFF;
    border-radius: 16px;
    overflow: hidden;
    box-shadow: 0px 4px 20px 0px rgba(75, 136, 249, 0.2);
  }
  .van-tabs /deep/ .van-cell__title {
    width: 90%;
  }
  .alarmTitle {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: #323233;
    font-size: 24px;
  }
  .alarmTitle .tag {
    font-size: 20px;
    margin-right: 8px;
    background-color: #4B88F9;
  }
  .time {
    color: #969799;
    font-size: 20px;
  }
</style>
src/pages/login.vue
New file
@@ -0,0 +1,164 @@
<template>
  <div class="loginDiv">
    <div class="logo-bg"></div>
    <div class="login-con">
      <div class="appName">成都石化告警APP</div>
      <div class="login-title">登录</div>
      <div class="lineInput">
        <img src="../assets/img/login-ico1.png" class="ico1">
        <van-field v-model="userName" placeholder="请输入账号" />
      </div>
      <div class="lineInput">
        <img src="../assets/img/login-ico2.png" class="ico2">
        <van-field v-model="password" placeholder="请输入密码" type="password" />
      </div>
      <div class="subBtn" @click="submit">登录</div>
    </div>
  </div>
</template>
<script>
  import {
    login
  } from "@/assets/js/api";
  export default {
    data() {
      return {
        userName: '',
        password: ''
      }
    },
    mounted() {
    },
    methods: {
      // 登录
      submit() {
        let self = this;
        if (self.userName == '') {
          self.$toast('请输入账号!')
          return
        }
        if (self.password == '') {
          self.$toast('请输入密码!')
          return
        }
        // 开启等待框
        login(self.userName, self.password).then(res => {
          // 对结果进行处理
          console.log(res)
          self.handleLogin(res)
        }).catch(error => {
          // 关闭等待
          // console.log(error);
          self.$toast("网络异常");
        });
      },
      // 登录验证
      handleLogin(res) {
        let self = this;
        // 关闭等待
        // this.loading = false;
        let rs = JSON.parse(res.data.result);
        if (rs.code == 1) {
          self.$toast("登录成功");
          sessionStorage.setItem('username', self.username);
          sessionStorage.setItem('userId', rs.data);
          self.$router.push({
            path: '/index'
          })
        } else {
          self.$toast(rs.msg);
        }
      },
    }
  }
</script>
<style scoped="scoped">
  .loginDiv {
    width: 100%;
    height: 100%;
    background: #ffffff;
    padding-top: 160px;
  }
  .logo-bg {
    width: 100%;
    height: 100%;
    background: url('../assets/img/logo-bg.png') 0 0 no-repeat;
    background-size: 100% 100%;
    position: absolute;
    left: 0;
    top: 0;
  }
  .login-con {
    width: 100%;
    padding: 0 70px;
    position: relative;
  }
  .appName {
    color: #ffffff;
    font-size: 48px;
    font-weight: bold;
    margin-bottom: 240px;
    width: 100%;
    text-align: center;
  }
  .login-title {
    width: 110px;
    height: 76px;
    line-height: 76px;
    font-size: 50px;
    font-weight: bold;
    color: #333;
    border-bottom: 8px solid #4B88F9;
    text-align: center;
    margin-bottom: 68px;
  }
  .lineInput {
    width: 100%;
    height: 88px;
    background-color: #f5f5f5;
    border-radius: 44px;
    margin-bottom: 40px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 40px;
  }
  .lineInput .ico1 {
    width: 25px;
    height: 31px;
  }
  .lineInput .ico2 {
    width: 26px;
    height: 31px;
  }
  .lineInput /deep/ .van-cell {
    background-color: transparent;
  }
  .subBtn {
    width: 100%;
    height: 88px;
    border-radius: 44px;
    background-image: linear-gradient(to right, #08aeec, #4B88F9);
    box-shadow: 0 10px 20px rgb(85 149 246 / 50%);
    display: flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
    font-size: 32px;
    margin-top: 50px;
  }
</style>
src/router/index.js
New file
@@ -0,0 +1,11 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import routes from './routes'
Vue.use(VueRouter);
const router = new VueRouter({
  routes
});
export default router;
src/router/routes.js
New file
@@ -0,0 +1,20 @@
export default [{
    path: '/',
    redirect: '/login'
}, {
    path: '/login',
    meta: {},
    component: (resolve) => require(['@/pages/login.vue'], resolve)
}, {
    path: '/index',
    meta: {},
    component: (resolve) => require(['@/pages/index.vue'], resolve)
}, {
    path: '/alarmDetails',
    meta: {},
    component: (resolve) => require(['@/pages/alarm-details.vue'], resolve)
}, {
    path: '/alarmHandle',
    meta: {},
    component: (resolve) => require(['@/pages/alarm-handle.vue'], resolve)
}, ];
src/store/index.js
New file
@@ -0,0 +1,13 @@
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
  state: {},
  mutations: {},
  actions: {},
  modules: {
  }
})
vue.config.js
New file
@@ -0,0 +1,4 @@
module.exports = {
    publicPath: './',
    productionSourceMap: false,
}