更新
BIN
components/qianziyu-select/.DS_Store
vendored
Normal file
166
components/qianziyu-select/qianziyu-select.vue
Normal file
@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<view>
|
||||
<u-popup :show="show" @close="cancel">
|
||||
<view class="title">{{popupTitle}}</view>
|
||||
<view style="padding: 20rpx;">
|
||||
<u-search v-if="showSearch" @custom="search" @search="search" :placeholder="placeholder"
|
||||
v-model="keyword"></u-search>
|
||||
<u-gap v-if="showSearch" height="15"></u-gap>
|
||||
<scroll-view :scroll-top="scrollTop" scroll-y="true" class="scroll-Y" @scrolltolower="$emit('lower')">
|
||||
|
||||
<!--单选-->
|
||||
<u-radio-group v-if="type == 'radio'" :borderBottom="true" iconPlacement="right" placement="column"
|
||||
@change="groupChange" v-model="radioValue">
|
||||
<u-radio :customStyle="{marginBottom: '12px'}" v-for="(item, index) in dataLists" :key="index"
|
||||
:label="item[name]" :name="index">
|
||||
</u-radio>
|
||||
</u-radio-group>
|
||||
|
||||
<!--多选-->
|
||||
<u-checkbox-group v-if="type == 'checkbox'" :borderBottom="true" placement="column"
|
||||
iconPlacement="right" @change="checkboxChange" v-model="checkboxValue">
|
||||
<u-checkbox :customStyle="{marginBottom: '12px',paddingBottom:'12px'}"
|
||||
v-for="(item, index) in dataLists" :key="index" :label="item[name]" :name="index">
|
||||
</u-checkbox>
|
||||
</u-checkbox-group>
|
||||
|
||||
</scroll-view>
|
||||
<u-gap height="45"></u-gap>
|
||||
<view class="bottons">
|
||||
<u-row>
|
||||
<u-col customStyle="padding:0 10rpx 20rpx 20rpx" span="6">
|
||||
<u-button @click="cancel">取消</u-button>
|
||||
</u-col>
|
||||
<u-col customStyle="padding:0 20rpx 20rpx 10rpx" span="6">
|
||||
<u-button @click="submit" type="primary" throttleTime="1000" :disabled="(JSON.stringify(radioData) === '{}') && (checkboxData.length === 0)">确认</u-button>
|
||||
</u-col>
|
||||
</u-row>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 公共选择下拉框,基于uview。支持下拉加载、列表搜索、单选|多选
|
||||
* @author qianziyu
|
||||
* @description 弹出层选择器,基于uview中u-popup实现
|
||||
* @property {Array} dataLists 数据列表
|
||||
* @property {String} name 列表显示的字段名
|
||||
* @property {Boolean} show 是否展示弹窗 (默认 false )
|
||||
* @property {String} type 选择类型 单选|多选 (默认 单选 )
|
||||
* @property {Boolean} showSearch 是否显示搜索框 (默认 true )
|
||||
* @property {String} popupTitle 列表标题
|
||||
* @property {String} placeholder 搜索框placeholder
|
||||
* @event {Function} search 搜索事件,返回keyword
|
||||
* @event {Function} lower 滑动到底部触发,用于下拉加载新数据
|
||||
* @event {Function} cancel 组件关闭事件
|
||||
* @event {Function} submit 提交按钮,返回选中的列表数据
|
||||
* @example <common-select :show="show" :popupTitle="popupTitle" @cancel="show=false" @search="selectSearch" name="cworkStationName" @submit="onsubmit"
|
||||
:dataLists="dataLists" placeholder="输入工站名称搜索"></common-select>
|
||||
*/
|
||||
export default {
|
||||
name: "qianziyu-select",
|
||||
props: {
|
||||
dataLists: {
|
||||
default: {},
|
||||
type: Array
|
||||
},
|
||||
name: {
|
||||
default: 'name',
|
||||
},
|
||||
show: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
type: {
|
||||
default: 'radio',
|
||||
type: String
|
||||
},
|
||||
showSearch: {
|
||||
default: true,
|
||||
type: Boolean
|
||||
},
|
||||
popupTitle: {
|
||||
default: '列表选择',
|
||||
type: String
|
||||
},
|
||||
placeholder: {
|
||||
default: '请输入搜索内容'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
keyword: '',
|
||||
scrollTop: 0,
|
||||
checkboxData: [],
|
||||
checkboxValue:[],
|
||||
radioData: {},
|
||||
radioValue: ''
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
checkboxChange(n) {
|
||||
this.checkboxData=[]
|
||||
n.forEach(key=>{
|
||||
this.checkboxData.push(this.dataLists[key])
|
||||
})
|
||||
},
|
||||
//选择列表项触发
|
||||
groupChange(n) {
|
||||
this.radioData = this.dataLists[n]
|
||||
},
|
||||
//点击搜索触发
|
||||
search() {
|
||||
this.$emit('search', this.keyword)
|
||||
},
|
||||
//点击取消按钮触发
|
||||
cancel() {
|
||||
this.$emit('cancel')
|
||||
},
|
||||
//提交触发
|
||||
submit() {
|
||||
if (this.type == 'radio') {
|
||||
if (JSON.stringify(this.radioData) == '{}') {
|
||||
uni.$u.toast('请选择数据')
|
||||
return;
|
||||
}
|
||||
this.$emit('submit', this.radioData)
|
||||
} else if (this.type == 'checkbox') {
|
||||
if (this.checkboxData.length == 0) {
|
||||
uni.$u.toast('请选择数据')
|
||||
return;
|
||||
}
|
||||
this.$emit('submit', this.checkboxData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.u-popup {
|
||||
.title {
|
||||
border-bottom: 1px solid #f7f7f7;
|
||||
padding: 20rpx;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-Y {
|
||||
height: 650rpx;
|
||||
}
|
||||
|
||||
.bottons {
|
||||
background-color: white;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
bottom: constant(safe-area-inset-bottom);
|
||||
bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
</style>
|
442
components/sin-signature/sin-signature.vue
Normal file
@ -0,0 +1,442 @@
|
||||
<template>
|
||||
<view class="signature-wrap">
|
||||
<view class="img-wrap" @tap="showSignature()" @touchstart="touchSignature()">
|
||||
<image :src="absPrevView" mode="scaleToFill"></image>
|
||||
</view>
|
||||
<view v-if="!disabled" v-show="show" class="signature-contain">
|
||||
<view class="signature-main" style="z-index: 3000;">
|
||||
<view class="signature-title"><text v-for="t in titles">{{t}}</text></view>
|
||||
<canvas disable-scroll="true" class="signature" :class="cid" canvas-id="cvs" @touchstart="touchstart"
|
||||
@touchmove="touchmove" @touchend="touchend"></canvas>
|
||||
<view class="signature-btns">
|
||||
<view class="btn btn-cancel cu-btn bg-main margin-tb-sm text-white" @tap="cancelSignature()">
|
||||
<text>取</text><text>消</text>
|
||||
</view>
|
||||
<view class="btn btn-clear cu-btn bg-main margin-tb-sm text-white" @tap="clearSignature();">
|
||||
<text>清</text><text>空</text>
|
||||
</view>
|
||||
<view class="btn btn-ok cu-btn bg-main margin-tb-sm text-white" @tap="onOK()">
|
||||
<text>确</text><text>定</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
let _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
var _utf8_encode = function(string) {
|
||||
string = string.replace(/\r\n/g, "\n");
|
||||
var utftext = "";
|
||||
for (var n = 0; n < string.length; n++) {
|
||||
var c = string.charCodeAt(n);
|
||||
if (c < 128) {
|
||||
utftext += String.fromCharCode(c);
|
||||
} else if ((c > 127) && (c < 2048)) {
|
||||
utftext += String.fromCharCode((c >> 6) | 192);
|
||||
utftext += String.fromCharCode((c & 63) | 128);
|
||||
} else {
|
||||
utftext += String.fromCharCode((c >> 12) | 224);
|
||||
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
|
||||
utftext += String.fromCharCode((c & 63) | 128);
|
||||
}
|
||||
|
||||
}
|
||||
return utftext;
|
||||
}
|
||||
|
||||
let base64encode = function(input) {
|
||||
var output = "";
|
||||
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
|
||||
var i = 0;
|
||||
input = _utf8_encode(input);
|
||||
while (i < input.length) {
|
||||
chr1 = input.charCodeAt(i++);
|
||||
chr2 = input.charCodeAt(i++);
|
||||
chr3 = input.charCodeAt(i++);
|
||||
enc1 = chr1 >> 2;
|
||||
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
||||
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
||||
enc4 = chr3 & 63;
|
||||
if (isNaN(chr2)) {
|
||||
enc3 = enc4 = 64;
|
||||
} else if (isNaN(chr3)) {
|
||||
enc4 = 64;
|
||||
}
|
||||
output = output +
|
||||
_keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
|
||||
_keyStr.charAt(enc3) + _keyStr.charAt(enc4);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
export default {
|
||||
cxt: null,
|
||||
data() {
|
||||
return {
|
||||
VERSION: '1.0.0',
|
||||
cid: 'cvs',
|
||||
show: false,
|
||||
ctrl: null,
|
||||
listeners: [],
|
||||
prevView: '',
|
||||
|
||||
draws: [],
|
||||
lines: [],
|
||||
line: null,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
default: '',
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '请签字',
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value() {
|
||||
this.prevView = this.value;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
titles() {
|
||||
return this.title.split('')
|
||||
},
|
||||
absPrevView() {
|
||||
var pv = this.prevView;
|
||||
// if(pv){
|
||||
// pv = this.$wrapUrl(pv)
|
||||
// }
|
||||
return pv;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.prevView = this.value;
|
||||
console.log('dx')
|
||||
},
|
||||
methods: {
|
||||
onOK() {
|
||||
let data = this.ctrl.getValue();
|
||||
this.$emit('input', data);
|
||||
this.prevView = data;
|
||||
this.hideSignature();
|
||||
let f = this.listeners.shift();
|
||||
if (f) {
|
||||
f(data);
|
||||
}
|
||||
},
|
||||
touchSignature() {
|
||||
let sig = this.prevView
|
||||
if (!sig || !sig.length) {
|
||||
this.showSignature()
|
||||
}
|
||||
},
|
||||
showSignature() {
|
||||
if (this.disabled)
|
||||
return;
|
||||
if (!this.ctrl) {
|
||||
this.initCtrl();
|
||||
} else if (!this.show) {
|
||||
this.clearSignature();
|
||||
this.show = true;
|
||||
}
|
||||
},
|
||||
async getSyncSignature() {
|
||||
this.showSignature();
|
||||
return await new Promise(async (resolve, reject) => {
|
||||
this.listeners.push((res) => {
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
},
|
||||
cancelSignature() {
|
||||
this.listeners.map((f) => {
|
||||
f(null);
|
||||
})
|
||||
this.hideSignature();
|
||||
},
|
||||
hideSignature() {
|
||||
this.ctrl && this.ctrl.clear();
|
||||
this.show = false;
|
||||
},
|
||||
clearSignature() {
|
||||
this.ctrl && this.ctrl.clear();
|
||||
},
|
||||
async initCtrl() {
|
||||
this.show = true;
|
||||
let cxt = uni.createCanvasContext(this.cid, this);
|
||||
this.cxt = cxt;
|
||||
// cxt.clearRect(0,0,c.width,c.height);
|
||||
this.ctrl = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
clear: () => {
|
||||
this.lines = [];
|
||||
let info = uni.createSelectorQuery().in(this).select("." + this.cid);
|
||||
info.boundingClientRect((data) => {
|
||||
if (data) {
|
||||
cxt.clearRect(0, 0, data.width, data.height);
|
||||
if (data.width && data.height) {
|
||||
this.ctrl.width = data.width;
|
||||
this.ctrl.height = data.height;
|
||||
}
|
||||
}
|
||||
}).exec();
|
||||
this.redraw();
|
||||
},
|
||||
getValue: () => {
|
||||
if (!this.lines.length)
|
||||
return '';
|
||||
let svg = this._get_svg();
|
||||
// new Buff
|
||||
let b64 = base64encode(svg);
|
||||
let data = 'data:image/svg+xml;base64,' + b64;
|
||||
// console.log(svg);
|
||||
// console.log(data);
|
||||
return data;
|
||||
},
|
||||
};
|
||||
this.$nextTick(function() {
|
||||
this.ctrl.clear();
|
||||
})
|
||||
},
|
||||
_get_svg() {
|
||||
let r = -90;
|
||||
let paths = [];
|
||||
let raww = this.ctrl.width;
|
||||
let rawh = this.ctrl.height;
|
||||
let width = Math.abs(r) != 90 ? raww : rawh;
|
||||
let height = Math.abs(r) == 90 ? raww : rawh;
|
||||
let cx = raww / 2;
|
||||
let cy = rawh / 2;
|
||||
let PI = Math.PI;
|
||||
let R = (r || 0) % 360;
|
||||
let cosv = Math.cos(R * PI / 180);
|
||||
let sinv = Math.sin(R * PI / 180);
|
||||
let dcx = (width - raww) / 2;
|
||||
let dcy = (height - rawh) / 2;
|
||||
let trans = function(p) {
|
||||
if (!R) {
|
||||
return p;
|
||||
} else {
|
||||
let nx = (p.x - cx) * cosv - (p.y - cy) * sinv + cx;
|
||||
let ny = (p.x - cx) * sinv + (p.y - cy) * cosv + cy;
|
||||
return {
|
||||
x: nx + dcx,
|
||||
y: ny + dcy
|
||||
};
|
||||
}
|
||||
return p;
|
||||
}
|
||||
this.lines.map(l => {
|
||||
if (l.points.length < 2) {
|
||||
return;
|
||||
}
|
||||
let sp = trans(l.start)
|
||||
let pts = [`M ${sp.x} ${Number(sp.y)}`];
|
||||
l.points.map(p => {
|
||||
let np = trans(p)
|
||||
pts.push(`L ${np.x} ${Number(np.y)}`);
|
||||
});
|
||||
paths.push(
|
||||
`<path stroke-linejoin="round" stroke-linecap="round" stroke-width="3" stroke="rgb(0,0,0)" fill="none" d="${pts.join(' ')}"/>`
|
||||
);
|
||||
})
|
||||
let svg =
|
||||
`<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="${width}" height="${height}">${paths.join('\n')}</svg>`;
|
||||
return svg;
|
||||
},
|
||||
_get_svg_raw() {
|
||||
let paths = [];
|
||||
this.lines.map(l => {
|
||||
if (l.points.length < 2) {
|
||||
return;
|
||||
}
|
||||
let pts = [`M ${l.start.x} ${Number(l.start.y)}`];
|
||||
l.points.map(p => {
|
||||
pts.push(`L ${p.x} ${Number(p.y)}`);
|
||||
});
|
||||
paths.push(
|
||||
`<path stroke-linejoin="round" stroke-linecap="round" stroke-width="3" stroke="rgb(0,0,0)" fill="none" d="${pts.join(' ')}"/>`
|
||||
);
|
||||
})
|
||||
let width = this.ctrl.width;
|
||||
let height = this.ctrl.height;
|
||||
let svg =
|
||||
`<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="${width}" height="${height}" transform="rotate(-90)">${paths.join('\n')}</svg>`;
|
||||
return svg;
|
||||
},
|
||||
_get_point(e) {
|
||||
return {
|
||||
x: e.changedTouches[0].x.toFixed(1),
|
||||
y: e.changedTouches[0].y.toFixed(1),
|
||||
}
|
||||
},
|
||||
touchstart(e) {
|
||||
let p = this._get_point(e);
|
||||
this.line = {
|
||||
start: p,
|
||||
points: [p],
|
||||
}
|
||||
this.lines.push(this.line);
|
||||
},
|
||||
touchmove(e) {
|
||||
let p = this._get_point(e);
|
||||
this.line.points.push(p)
|
||||
if (!this.tm) {
|
||||
this.tm = setTimeout(() => {
|
||||
this.redraw();
|
||||
this.tm = 0;
|
||||
}, 10)
|
||||
}
|
||||
},
|
||||
touchend(e) {
|
||||
let p = this._get_point(e);
|
||||
this.line.points.push(p)
|
||||
this.line.end = p
|
||||
this.redraw()
|
||||
},
|
||||
redraw() {
|
||||
let cxt = this.cxt;
|
||||
cxt.setStrokeStyle("#000");
|
||||
cxt.setLineWidth(3);
|
||||
var last = null;
|
||||
this.lines.map(l => {
|
||||
cxt.beginPath();
|
||||
if (l.points.length < 2) {
|
||||
return;
|
||||
}
|
||||
cxt.moveTo(l.start.x, l.start.y);
|
||||
l.points.map(p => {
|
||||
cxt.lineTo(p.x, p.y)
|
||||
})
|
||||
cxt.stroke()
|
||||
})
|
||||
|
||||
cxt.draw()
|
||||
},
|
||||
canvasIdErrorCallback: function(e) {
|
||||
console.error(e.detail.errMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.signature-wrap {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
// padding: 0 5px;
|
||||
|
||||
// min-width: 60vw;
|
||||
.img-wrap {
|
||||
width: 100%;
|
||||
min-height: 200rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
// background: red;
|
||||
}
|
||||
}
|
||||
|
||||
.signature-contain {
|
||||
z-index: 9000;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
|
||||
.signature-main {
|
||||
background: white;
|
||||
flex-direction: row-reverse;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
height: 101%;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.signature-title {
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
display: flex;
|
||||
padding: 0 20rpx;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
color: $uni-text-color;
|
||||
|
||||
text {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
|
||||
.signature {
|
||||
border: 1px dotted black;
|
||||
border-bottom: 1px dotted black;
|
||||
background: #FFF;
|
||||
margin: 10px 0;
|
||||
width: 90vw;
|
||||
height: 90vh;
|
||||
align-self: center;
|
||||
// pointer-events:none;
|
||||
}
|
||||
|
||||
.signature-btns {
|
||||
display: flex;
|
||||
padding: 2px;
|
||||
// margin-right: 5px;
|
||||
flex-direction: column;
|
||||
|
||||
.btn {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 0;
|
||||
padding: 20rpx;
|
||||
font-size: 20px;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
height: 30vh;
|
||||
display: flex;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
|
||||
text {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
&+.btn {
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
&.btn-clear {
|
||||
// background-color: #fc2a07;
|
||||
color: $uni-color-success;
|
||||
}
|
||||
|
||||
&.btn-cancel {
|
||||
// background-color: #eff4f4;
|
||||
color: $uni-color-warning;
|
||||
}
|
||||
|
||||
&.btn-ok {
|
||||
// background-color: $uni-color-success;
|
||||
color: $uni-color-primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
216
pages-business/businessInfo/businessInfo.vue
Normal file
@ -0,0 +1,216 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<!-- 顶部背景 -->
|
||||
<view class="header">
|
||||
<image class="bg-img" src="/static/images/table_header.png" mode="aspectFill"></image>
|
||||
<view style="display: flex;align-items: center;padding-left: 20rpx;">
|
||||
<uni-icons style="position: absolute;left: 30rpx;" @click="goBack" type="left" color="black"
|
||||
size="24"></uni-icons>
|
||||
</view>
|
||||
<view class="title">{{title}}业务总览</view>
|
||||
</view>
|
||||
|
||||
<!-- 表格 -->
|
||||
|
||||
<uni-table emptyText="暂无更多数据" style="margin-top: 30rpx;">
|
||||
<!-- 表头行 -->
|
||||
<uni-tr style="background: #E5EEFF;">
|
||||
<uni-th>车辆信息</uni-th>
|
||||
<uni-th>业务</uni-th>
|
||||
<!-- <uni-th>渠道</uni-th> -->
|
||||
<uni-th>来源</uni-th>
|
||||
<uni-th>经办人</uni-th>
|
||||
<uni-th>办理时间</uni-th>
|
||||
<uni-th>付款状态</uni-th>
|
||||
</uni-tr>
|
||||
<!-- 表格数据行 -->
|
||||
<uni-tr v-for="(item,index) in list" :key="index" class="table-row" @click.native="goWorkDetail(item)"
|
||||
:class="{'row-bg': index % 2 === 1}">
|
||||
<uni-td>{{ item.carNo }}</uni-td>
|
||||
<uni-td>{{ item.sourceStr }}</uni-td>
|
||||
<!-- <uni-td>{{ item.channel }}</uni-td> -->
|
||||
<uni-td>{{ item.busiFrom }}</uni-td>
|
||||
<uni-td>{{ item.handleName }}</uni-td>
|
||||
<uni-td>{{ formatDateTimeToMinute(item.createTime) }}</uni-td>
|
||||
<uni-td>{{ dictData[item.payStatus] }}</uni-td>
|
||||
</uni-tr>
|
||||
|
||||
</uni-table>
|
||||
<uni-pagination :current="current" :pageSize="queryParams.pageSize" :total="total"
|
||||
@change="onPageChange"></uni-pagination>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '../../utils/request';
|
||||
import {
|
||||
formatDateTimeToMinute,
|
||||
getDictTextByCodeAndValue,
|
||||
getDictByCode
|
||||
} from '@/utils/utils.js'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
data: undefined,
|
||||
queryParams: {
|
||||
pageSize: 15,
|
||||
pageNo: 1
|
||||
},
|
||||
title: '',
|
||||
total: 0,
|
||||
current: 0,
|
||||
safeLeft: 0,
|
||||
dictData: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatDateTimeToMinute,
|
||||
getDictTextByCodeAndValue,
|
||||
goBack() {
|
||||
uni.redirectTo({
|
||||
url: '/pages/white/white'
|
||||
});
|
||||
},
|
||||
async getDict() {
|
||||
const list = await getDictByCode('repair_pay_status')
|
||||
this.dictData = list?.reduce((map, item) => {
|
||||
map[item.value] = item.label
|
||||
return map
|
||||
}, {}) ?? {} // 如果 list 为空或 reduce 返回 undefined,则使用空对象
|
||||
console.log('dict', this.dictData)
|
||||
},
|
||||
getList() {
|
||||
request({
|
||||
url: `/admin-api/repair/statistics/pageByCustomerOrCar`,
|
||||
params: this.queryParams
|
||||
}).then(res => {
|
||||
this.list = res.data.records
|
||||
this.total = res.data.total
|
||||
this.current = res.data.current
|
||||
})
|
||||
},
|
||||
onPageChange(e) {
|
||||
this.queryParams.pageNo = e.current
|
||||
this.getList()
|
||||
},
|
||||
goWorkDetail(data) {
|
||||
console.log('执行');
|
||||
// 退出时恢复自动(或者你项目里默认的方向)
|
||||
// #ifdef APP-PLUS
|
||||
plus.screen.lockOrientation('portrait-primary'); //锁死屏幕方向为竖屏
|
||||
plus.navigator.setFullscreen(false);
|
||||
// #endif
|
||||
const innerUrl = `/pages-order/orderDetail/orderDetail?id=${data.id}&isDetail=1`
|
||||
// const url = `/pages-business/white/newWhite?url=${encodeURIComponent(innerUrl)}`
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url: innerUrl
|
||||
})
|
||||
}, 1000); // 300毫秒延时,可以根据需要调整
|
||||
}
|
||||
},
|
||||
onShow() {},
|
||||
//页面显示时切换为横屏配置
|
||||
onLoad(options) {
|
||||
this.getDict()
|
||||
console.log('传进来的数据', options);
|
||||
if (options.data) {
|
||||
const queryParams = JSON.parse(decodeURIComponent(options.data));
|
||||
this.data = queryParams
|
||||
if (options.type == 'customer') {
|
||||
this.queryParams.phone = queryParams.customerPhone
|
||||
this.title = queryParams.customerName
|
||||
} else {
|
||||
this.queryParams.carNo = queryParams.carNum
|
||||
this.title = queryParams.carNum
|
||||
}
|
||||
this.getList()
|
||||
}
|
||||
},
|
||||
// 监听页面返回
|
||||
onBackPress() {
|
||||
console.log('执行跳转');
|
||||
// 跳转至空白页
|
||||
uni.redirectTo({
|
||||
url: '/pages/white/white'
|
||||
});
|
||||
return true;
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: white;
|
||||
padding-left: env(safe-area-inset-left);
|
||||
|
||||
}
|
||||
|
||||
/* 顶部背景和标题 */
|
||||
.header {
|
||||
display: flex;
|
||||
position: relative;
|
||||
height: 100rpx;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 20rpx 40rpx;
|
||||
padding-top: var(--status-bar-height); //给组件加个上边距
|
||||
}
|
||||
|
||||
.bg-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
/* z-index: -1; */
|
||||
}
|
||||
|
||||
.title {
|
||||
text-align: center;
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
line-height: 100rpx;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* 表格 */
|
||||
.table {
|
||||
margin: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.table-row {
|
||||
/* flex-direction: row;
|
||||
display: flex; */
|
||||
}
|
||||
|
||||
.table-header {
|
||||
background-color: #f2f6ff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.table-cell {
|
||||
flex: 1;
|
||||
padding: 20rpx;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.row-bg {
|
||||
background-color: #f9fbff;
|
||||
}
|
||||
|
||||
.status {
|
||||
color: #d4a017;
|
||||
/* 金色 */
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
745
pages-business/businessManage/businessManage.vue
Normal file
@ -0,0 +1,745 @@
|
||||
<template>
|
||||
<view class="business-management">
|
||||
<!-- 业务总览头部 -->
|
||||
<view class="header" style="position: relative;">
|
||||
<view style="display: flex;">
|
||||
<uni-icons style="position: absolute;left: 0;" @click="goBack" type="left" color="white"
|
||||
size="24"></uni-icons>
|
||||
<text class="title">业务管理</text>
|
||||
</view>
|
||||
<view class="subtitle">
|
||||
<view class="text_">
|
||||
<image style="height: 40rpx;width: 8rpx;" src="/static/images/business/text_left.png"></image>
|
||||
<view>
|
||||
业务总览
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<uni-datetime-picker v-model="queryParams.dateRange" type="daterange" @change="initData()"
|
||||
rangeSeparator="至" class="">
|
||||
<view class="cont_time">
|
||||
<view class="cont_size">{{queryParams.dateRange[0]}}</view>
|
||||
<view class="bule_size">~</view>
|
||||
<view class="cont_size">{{queryParams.dateRange[1]}}</view>
|
||||
<view class=""> <u-icon name="arrow-down-fill" color="#0357FF" size="12"></u-icon></view>
|
||||
</view>
|
||||
</uni-datetime-picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 数据卡片 -->
|
||||
<view class="data-cards">
|
||||
<!-- 选项卡 -->
|
||||
<view class="tabs">
|
||||
<view class="tab" :class="{'active':tapIndex == index}" v-for="(item,index) in tapList" :key="index"
|
||||
@click="tapIcon(index)">
|
||||
<view class="">{{item.label || "无"}}</view>
|
||||
<view class="tap_img" style="display: block;width: 30rpx;" v-show="tapIndex == index">
|
||||
<image src="/static/images/icon_tap.png" mode="widthFix" class="tap_icon"></image>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-row-1">
|
||||
<view class="data-card">
|
||||
<text class="card-value">进厂数</text>
|
||||
<text class="card-label">{{ bossNum.newOrderNum }}</text>
|
||||
</view>
|
||||
<view class="data-card">
|
||||
<text class="card-value">维修中</text>
|
||||
<text class="card-label">{{ bossNum.workingNum }}</text>
|
||||
</view>
|
||||
<view class="data-card">
|
||||
<text class="card-value">已竣工</text>
|
||||
<text class="card-label">{{ bossNum.overNum }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="card-row-2">
|
||||
<view class="data-card">
|
||||
<text class="card-value">已交车</text>
|
||||
<text class="card-label">{{ bossNum.giveCusNum }}</text>
|
||||
</view>
|
||||
<view class="data-card">
|
||||
<text class="card-value">未结算</text>
|
||||
<text class="card-label">{{ bossNum.noPayNum }}</text>
|
||||
</view>
|
||||
<view class="data-card">
|
||||
<text class="card-value">在厂数</text>
|
||||
<text class="card-label">{{ bossNum.inCompanyNum }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="business_title">
|
||||
<!-- 选项卡 -->
|
||||
<view class="tabs">
|
||||
<view class="tab" :class="{'active':busTapIndex == index}" v-for="(item,index) in busTapList"
|
||||
:key="index" @click="tapBusIcon(index)">
|
||||
<view class="">{{item.label || "无"}}</view>
|
||||
<view class="tap_img" style="display: block;" v-show="busTapIndex == index">
|
||||
<image src="/static/images/icon_tap.png" mode="widthFix" class="tap_icon"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="">
|
||||
<uni-search-bar radius="50" bgColor="#F8F4FF" @confirm="onRefresherrefresh"
|
||||
v-model="queryParams.search" @cancel="onRefresherrefresh" @clear="onRefresherrefresh"
|
||||
placeholder="请输入搜索内容"></uni-search-bar>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<view class="list">
|
||||
<!-- 客户列表 -->
|
||||
<scroll-view class="client-list" scroll-y style="height:100%" @scrolltolower="onReachBottomCus"
|
||||
refresher-enabled @refresherrefresh="onRefresherrefresh" :refresher-triggered="isTriggered">
|
||||
<view class="client-item" v-for="(item,index) in busList" :key="index" @click="goDetail(item)">
|
||||
<view class="last-time">
|
||||
<view class="">
|
||||
最近办理业务时间:{{item.bizTime}}
|
||||
</view>
|
||||
<view class="">
|
||||
次数:{{item.consumeCount}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="card_bottom">
|
||||
<view class="info_left">
|
||||
<view class="user_">
|
||||
<view class="client-name" v-if="busTapIndex == 0">{{item.customerName}}</view>
|
||||
<view class="client-name" v-else>{{item.carNum}}</view>
|
||||
<view class="agent" v-if="busTapIndex == 0">经办人:{{item.handleName}}</view>
|
||||
<view class="agent" v-else>{{item.customerName}}</view>
|
||||
</view>
|
||||
<view class="phone">联系电话:{{item.customerPhone}}</view>
|
||||
</view>
|
||||
<view class="info_right">
|
||||
<view class="top_text">{{item.sourceStr}}</view>
|
||||
<view class="bottom_text">
|
||||
最近办理业务
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view style="text-align: center" v-if="busList.length==0">
|
||||
<image class="" src="@/static/images/nothing.png"></image>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '../../utils/request'
|
||||
import {
|
||||
getDateRange
|
||||
} from '../../utils/utils'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
searchKeyword: '',
|
||||
//下来刷新状态
|
||||
isTriggered: true,
|
||||
tapList: [{
|
||||
label: "本日",
|
||||
value: "day",
|
||||
},
|
||||
{
|
||||
label: "本月",
|
||||
value: "month",
|
||||
},
|
||||
{
|
||||
label: "全部",
|
||||
value: "all",
|
||||
},
|
||||
],
|
||||
busTapList: [{
|
||||
label: "客户",
|
||||
value: "customer",
|
||||
},
|
||||
{
|
||||
label: "车辆",
|
||||
value: "car",
|
||||
}
|
||||
],
|
||||
tapIndex: 0,
|
||||
busTapIndex: 0,
|
||||
queryParams: {
|
||||
dateRange: [],
|
||||
type: 'customer',
|
||||
selectType: 'today',
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
search: null
|
||||
},
|
||||
bossNum: {},
|
||||
busList: [],
|
||||
}
|
||||
},
|
||||
async onLoad() {
|
||||
await this.setCurrentMonthRange()
|
||||
await this.initData()
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
uni.navigateBack()
|
||||
},
|
||||
async tapIcon(index) {
|
||||
this.tapIndex = index
|
||||
await this.slectRange(index)
|
||||
await this.initData()
|
||||
},
|
||||
tapBusIcon(index) {
|
||||
this.busTapIndex = index
|
||||
this.queryParams.type = this.busTapList[index].value
|
||||
this.queryParams.pageNo = 1
|
||||
this.busList = []
|
||||
this.getList()
|
||||
},
|
||||
/**
|
||||
* 初始化数据
|
||||
*/
|
||||
initData() {
|
||||
this.getNum()
|
||||
this.onRefresherrefresh()
|
||||
},
|
||||
getNum() {
|
||||
request({
|
||||
url: '/admin-api/repair/tickets/getBossNumNew',
|
||||
method: 'get',
|
||||
params: this.queryParams
|
||||
}).then((res) => {
|
||||
console.log(res)
|
||||
if (res.code == 200) {
|
||||
this.bossNum = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getList() {
|
||||
request({
|
||||
url: '/admin-api/repair/statistics/listBusiness',
|
||||
method: 'get',
|
||||
params: this.queryParams
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
if (this.queryParams.pageNo == 1) {
|
||||
this.busList = res.data.records
|
||||
} else {
|
||||
this.busList.push(...res.data.records)
|
||||
}
|
||||
}
|
||||
//将获取的总条数赋值
|
||||
this.total = res.data.total
|
||||
this.isTriggered = false
|
||||
})
|
||||
},
|
||||
clear() {},
|
||||
cancel() {},
|
||||
// 设置本月起止日期:月初到今天
|
||||
setCurrentMonthRange() {
|
||||
// 直接使用 Date 对象
|
||||
const now = new Date();
|
||||
|
||||
// 创建月初的 Date 对象
|
||||
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
|
||||
this.queryParams.dateRange = [
|
||||
this.formatDate(now), // 月初
|
||||
this.formatDate(now), // 今天
|
||||
];
|
||||
},
|
||||
formatDate(d) {
|
||||
// 添加类型检查,确保 d 是 Date 对象
|
||||
if (!(d instanceof Date)) {
|
||||
console.error("formatDate() 期望接收 Date 对象,但收到:", d);
|
||||
d = new Date(d); // 尝试转换为 Date 对象
|
||||
if (isNaN(d.getTime())) {
|
||||
// 检查是否有效日期
|
||||
d = new Date(); // 如果转换失败,使用当前日期
|
||||
}
|
||||
}
|
||||
return `${d.getFullYear()}-${this.pad(d.getMonth() + 1)}-${this.pad(
|
||||
d.getDate()
|
||||
)}`;
|
||||
},
|
||||
// 补零:1 → 01
|
||||
pad(n) {
|
||||
return n.toString().padStart(2, "0");
|
||||
},
|
||||
slectRange(index) {
|
||||
this.selected = index;
|
||||
console.log(index, this.selected);
|
||||
const {
|
||||
value
|
||||
} = this.tapList[index];
|
||||
console.log(value);
|
||||
this.queryParams.dateRange = getDateRange(value);
|
||||
},
|
||||
/**
|
||||
* 上滑加载数据
|
||||
*/
|
||||
onReachBottomCus() {
|
||||
//判断 如果页码*页容量大于等于总条数,提示该页数据加载完毕
|
||||
if (this.queryParams.pageNo * this.queryParams.pageSize >= this.total) {
|
||||
uni.$u.toast('没有更多数据了')
|
||||
return
|
||||
}
|
||||
//页码+1,调用获取数据的方法获取第二页数据
|
||||
this.queryParams.pageNo++
|
||||
//此处调用自己获取数据列表的方法
|
||||
this.getList()
|
||||
},
|
||||
/**
|
||||
* 下拉刷新数据
|
||||
*/
|
||||
async onRefresherrefresh() {
|
||||
this.isTriggered = true
|
||||
this.pageNo = 1
|
||||
this.total = 0
|
||||
this.busList = []
|
||||
await this.getList()
|
||||
},
|
||||
goDetail(data) {
|
||||
uni.navigateTo({
|
||||
url: `/pages-business/businessInfo/businessInfo?type=${this.queryParams.type}&data=${encodeURIComponent(JSON.stringify(data))}`
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* 全局样式 */
|
||||
page {
|
||||
background-color: #f5f5f5;
|
||||
padding: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.business-management {
|
||||
/* padding: 20rpx; */
|
||||
background: #F2F5FE;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* 头部样式 */
|
||||
.header {
|
||||
margin-bottom: 30rpx;
|
||||
background: linear-gradient(180deg, #1A53FF 0%, #F2F5FE 100%);
|
||||
/* height: 672rpx; */
|
||||
color: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0 30rpx;
|
||||
padding-top: calc(var(--status-bar-height) + 20rpx);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
margin-top: 20rpx;
|
||||
|
||||
.text_ {
|
||||
display: flex;
|
||||
|
||||
view {
|
||||
width: 112rpx;
|
||||
height: 28rpx;
|
||||
font-family: SourceHanSansCN, SourceHanSansCN;
|
||||
font-weight: 800;
|
||||
font-size: 28rpx;
|
||||
color: #FFFFFF;
|
||||
line-height: 42rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
image {
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.date-range {
|
||||
width: 386rpx;
|
||||
height: 56rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 36rpx;
|
||||
text-align: center;
|
||||
|
||||
.header {
|
||||
|
||||
width: 124rpx;
|
||||
height: 24rpx;
|
||||
font-family: SourceHanSansCN, SourceHanSansCN;
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #686C7A;
|
||||
line-height: 36rpx;
|
||||
text-align: right;
|
||||
font-style: normal;
|
||||
margin: auto 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* 选项卡样式 */
|
||||
.tabs {
|
||||
display: flex;
|
||||
margin-bottom: 30rpx;
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.tab {
|
||||
margin-right: 40rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
padding: 10rpx 0;
|
||||
|
||||
width: 56rpx;
|
||||
height: 28rpx;
|
||||
font-family: SourceHanSansCN, SourceHanSansCN;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #707677;
|
||||
line-height: 42rpx;
|
||||
text-align: right;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
color: #007AFF;
|
||||
font-weight: bold;
|
||||
|
||||
width: 56rpx;
|
||||
height: 28rpx;
|
||||
font-family: SourceHanSansCN, SourceHanSansCN;
|
||||
font-weight: bold;
|
||||
font-size: 28rpx;
|
||||
color: #292D2E;
|
||||
line-height: 42rpx;
|
||||
text-align: right;
|
||||
font-style: normal;
|
||||
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
/* 数据卡片样式 */
|
||||
.data-cards {
|
||||
margin: 20rpx 0;
|
||||
background: linear-gradient(180deg, #E4EFFF 0%, #FFFFFF 100%);
|
||||
box-shadow: 0rpx 4rpx 16rpx 0rpx rgba(167, 179, 229, 0.25);
|
||||
border-radius: 8rpx;
|
||||
width: 726rpx;
|
||||
/* height: 366rpx; */
|
||||
padding: 20rpx 10rpx;
|
||||
}
|
||||
|
||||
|
||||
.card-row-1 {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.data-card {
|
||||
height: 112rpx;
|
||||
width: 226rpx;
|
||||
background: linear-gradient(180deg, #D3EFFF 0%, #E3F3FF 100%);
|
||||
border-radius: 8rpx;
|
||||
|
||||
.card-value {
|
||||
width: 84rpx;
|
||||
height: 28rpx;
|
||||
font-family: SourceHanSansCN, SourceHanSansCN;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #14557E;
|
||||
line-height: 42rpx;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.card-label {
|
||||
width: 52rpx;
|
||||
height: 28rpx;
|
||||
font-family: SourceHanSansCN, SourceHanSansCN;
|
||||
font-weight: bold;
|
||||
font-size: 28rpx;
|
||||
color: #3E4045;
|
||||
line-height: 42rpx;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-row-2 {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.data-card {
|
||||
height: 112rpx;
|
||||
width: 226rpx;
|
||||
background: linear-gradient(180deg, #D8E6FF 0%, #EDF6FF 100%);
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.card-value {
|
||||
width: 84rpx;
|
||||
height: 28rpx;
|
||||
font-family: SourceHanSansCN, SourceHanSansCN;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #14557E;
|
||||
line-height: 42rpx;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.card-label {
|
||||
width: 52rpx;
|
||||
height: 28rpx;
|
||||
font-family: SourceHanSansCN, SourceHanSansCN;
|
||||
font-weight: bold;
|
||||
font-size: 28rpx;
|
||||
color: #3E4045;
|
||||
line-height: 42rpx;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.data-card {
|
||||
flex: 1;
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx 20rpx;
|
||||
margin: 0 10rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.card-value {
|
||||
font-size: 40rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.card-label {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 客户区域样式 */
|
||||
.client-section {
|
||||
background-color: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.section-subtitle {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 10rpx;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
margin-left: 15rpx;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 客户列表样式 */
|
||||
.client-list {
|
||||
max-height: 60vh;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.client-item {
|
||||
background: #FFFFFF;
|
||||
border-radius: 8rpx;
|
||||
padding: 20rpx 15rpx;
|
||||
|
||||
margin-bottom: 30rpx
|
||||
}
|
||||
|
||||
.client-name {
|
||||
font-family: SourceHanSansCN, SourceHanSansCN;
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.agent {
|
||||
font-family: SourceHanSansCN, SourceHanSansCN;
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #0357FF;
|
||||
line-height: 36rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
||||
background-color: #DCE7FF;
|
||||
border-radius: 20rpx;
|
||||
padding: 0 10rpx;
|
||||
}
|
||||
|
||||
|
||||
.phone {
|
||||
width: 312rpx;
|
||||
height: 28rpx;
|
||||
font-family: SourceHanSansCN, SourceHanSansCN;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #8F9197;
|
||||
line-height: 42rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/*
|
||||
.last-time {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
display: block;
|
||||
margin-bottom: 10rpx;
|
||||
} */
|
||||
|
||||
.last-time {
|
||||
border-bottom: 1px dashed #000;
|
||||
padding-bottom: 50rpx;
|
||||
width: 100%;
|
||||
|
||||
height: 24rpx;
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #7E8390;
|
||||
line-height: 36rpx;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.tap_img {
|
||||
height: 6rpx;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
|
||||
image {
|
||||
width: 34rpx;
|
||||
height: 12rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.cont_time {
|
||||
background: #F1F4F7;
|
||||
border-radius: 36rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0px 30rpx;
|
||||
|
||||
width: 386rpx;
|
||||
height: 56rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 36rpx;
|
||||
}
|
||||
|
||||
.cont_size {
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #686C7A;
|
||||
}
|
||||
|
||||
.business_title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 100rpx;
|
||||
}
|
||||
|
||||
.user_ {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.card_bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 20rpx 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info_right {
|
||||
text-align: right;
|
||||
color: black;
|
||||
|
||||
.top_text {
|
||||
font-family: SourceHanSansCN, SourceHanSansCN;
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #323439;
|
||||
line-height: 42rpx;
|
||||
}
|
||||
|
||||
.bottom_text {
|
||||
font-family: SourceHanSansCN, SourceHanSansCN;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #686B71;
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
padding: 20rpx;
|
||||
height: calc(100vh - 800rpx);
|
||||
}
|
||||
|
||||
.tap_icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
</style>
|
896
pages-business/statistics/statistics.vue
Normal file
@ -0,0 +1,896 @@
|
||||
<template>
|
||||
<view class="container">
|
||||
<!-- 顶部背景 -->
|
||||
<view class="header">
|
||||
<image class="bg-img" src="/static/images/table_header.png" mode="aspectFill"></image>
|
||||
<view style="display: flex;align-items: center;padding-left: 20rpx;">
|
||||
<uni-icons style="position: absolute;left: 30rpx;" @click="goBack" type="left" color="black"
|
||||
size="24"></uni-icons>
|
||||
</view>
|
||||
<view class="title">数据统计({{total}})</view>
|
||||
</view>
|
||||
<view class="content_top">
|
||||
<!-- 选项卡 -->
|
||||
<view class="tabs">
|
||||
<view class="tab" :class="{'active':tapIndex == index}" v-for="(item,index) in tapList" :key="index"
|
||||
@click="tapIcon(index)">
|
||||
<view class="">{{item.label || "无"}}</view>
|
||||
<view class="tap_img" style="display: block;" v-show="tapIndex == index">
|
||||
<image src="/static/images/icon_tap.png" mode="widthFix" class="tap_icon"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view style="display: flex;">
|
||||
<view class="search">
|
||||
<picker @change="bindTimeTypeChange" range-key="label" :value="timeTypeIndex"
|
||||
:range="timeTypeArray">
|
||||
<view class="uni-input border_" style="padding: 5rpx 20rpx;display: flex;">
|
||||
{{timeTypeArray[timeTypeIndex].label}}
|
||||
<view class=""> <u-icon name="arrow-down-fill" color="#0357FF" size="12"></u-icon></view>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view style="align-items: center;display: flex; border-radius: 50rpx;">
|
||||
<uni-datetime-picker v-model="queryParams.searchTimeArray" type="daterange"
|
||||
@change="queryParams.pageNo=1;initData()" rangeSeparator="至" class="">
|
||||
<view class="cont_time" style="border: 1px solid #0357FF;"
|
||||
v-if="queryParams.searchTimeArray.length>0">
|
||||
<view class="cont_size">{{queryParams.searchTimeArray[0]}}</view>
|
||||
<view class="bule_size">~</view>
|
||||
<view class="cont_size">{{queryParams.searchTimeArray[1]}}</view>
|
||||
<view class=""> <u-icon name="arrow-down-fill" color="#0357FF" size="12"></u-icon></view>
|
||||
</view>
|
||||
<view v-else class="cont_time border_">
|
||||
全部
|
||||
<view class=""> <u-icon name="arrow-down-fill" color="#0357FF" size="12"></u-icon></view>
|
||||
</view>
|
||||
</uni-datetime-picker>
|
||||
</view>
|
||||
<view class="search" @click="screening">
|
||||
筛选
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 表格 -->
|
||||
<view class="" style="padding-left: 30rpx;">
|
||||
<view class="census" v-if="checkPermi(['repair:tick:profit'])">
|
||||
<span class="credited">产值{{ laborPartsMoney }}元</span>
|
||||
<span class="notCredited">毛利 : {{ totalProfit }}元</span>
|
||||
<span
|
||||
class="onlinePay">含工时毛利率 : {{ statisticsInfo && statisticsInfo.profitRateWithLabor !== null && statisticsInfo.profitRateWithLabor !== undefined && !isNaN(statisticsInfo.profitRateWithLabor) ? (statisticsInfo.profitRateWithLabor * 100).toFixed(2) : '0.00' }}
|
||||
%</span>
|
||||
<span
|
||||
class="cashPay">不含工时毛利率 : {{ statisticsInfo && statisticsInfo.profitRateWithoutLabor !== null && statisticsInfo.profitRateWithoutLabor !== undefined && !isNaN(statisticsInfo.profitRateWithoutLabor) ? (statisticsInfo.profitRateWithoutLabor * 100).toFixed(2) : '0.00' }}
|
||||
%</span>
|
||||
</view>
|
||||
<uni-table emptyText="暂无更多数据">
|
||||
<!-- 表头行 -->
|
||||
<uni-tr style="background: #E5EEFF;">
|
||||
<uni-th>车辆信息</uni-th>
|
||||
<!-- <uni-th>业务</uni-th> -->
|
||||
<!-- <uni-th>渠道</uni-th> -->
|
||||
<uni-th>经办人</uni-th>
|
||||
<uni-th>经办人手机号</uni-th>
|
||||
<uni-th>进场时间</uni-th>
|
||||
<uni-th>付款状态</uni-th>
|
||||
<uni-th>结算时间</uni-th>
|
||||
</uni-tr>
|
||||
<!-- 表格数据行 -->
|
||||
<uni-tr v-for="(item,index) in list" :key="index" class="table-row" @click.native="goWorkDetail(item)"
|
||||
:class="{'row-bg': index % 2 === 1}">
|
||||
<uni-td>{{ item.carNo }}</uni-td>
|
||||
<!-- <uni-td>{{ item.sourceStr }}</uni-td> -->
|
||||
<!-- <uni-td>{{ item.channel }}</uni-td> -->
|
||||
<uni-td>{{ item.handleName }}</uni-td>
|
||||
<uni-td>{{ item.handleMobile }}</uni-td>
|
||||
<uni-td>{{ formatDateTimeToMinute(item.createTime) }}</uni-td>
|
||||
<uni-td>{{ dictData[item.payStatus] }}</uni-td>
|
||||
<uni-td>{{ item.settlementTime ? formatDateTimeToMinute(item.settlementTime) : '' }}</uni-td>
|
||||
</uni-tr>
|
||||
|
||||
</uni-table>
|
||||
<uni-pagination :current="current" :pageSize="queryParams.pageSize" :total="total"
|
||||
@change="onPageChange"></uni-pagination>
|
||||
</view>
|
||||
|
||||
<!-- 筛选弹窗 -->
|
||||
<uni-popup ref="popup" type="right" background-color="#fff">
|
||||
<view class="popup">
|
||||
<!-- 添加滚动区域 -->
|
||||
<scroll-view class="popup-content" scroll-y="true">
|
||||
<view class="reset" @click="resetQueryParams">
|
||||
<uni-icons type="loop" color="#165DFF"></uni-icons>
|
||||
重置筛选
|
||||
</view>
|
||||
<view>
|
||||
<uni-search-bar radius="50" bgColor="#F8F4FF" @confirm="queryParams.pageNo=1;initData()()"
|
||||
v-model="queryParams.ticketNo" @cancel="initData()" @clear="initData()"
|
||||
placeholder="请输入关键字"></uni-search-bar>
|
||||
</view>
|
||||
<uni-forms labelPosition="top" class="body-top-tab">
|
||||
<uni-forms-item label="业务渠道">
|
||||
<picker @change="bindBusiChange" :value="busiIndex" :range="busiList">
|
||||
<view class="uni-input">{{busiList[busiIndex]}}</view>
|
||||
</picker>
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="维修类别">
|
||||
<picker @change="bindRepairTypeChange" :value="repairTypeIndex" :range="repairTypeList">
|
||||
<view class="uni-input">{{repairTypeList[repairTypeIndex]}}</view>
|
||||
</picker>
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="工种类型">
|
||||
<picker @change="bindWorkTypeChange" :value="workTypeIndex" :range="workeTypeList">
|
||||
<view class="uni-input">{{workeTypeList[workTypeIndex]}}</view>
|
||||
</picker>
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="工单状态">
|
||||
<picker @change="bindTicketsStatusChange" :value="ticketsStatusIndex"
|
||||
:range="ticketsStatusList">
|
||||
<view class="uni-input">{{ticketsStatusList[ticketsStatusIndex]}}</view>
|
||||
</picker>
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="来源">
|
||||
<uni-data-picker :localdata="cusFromList" v-model='queryParams.cusFrom'
|
||||
popup-title="请选择渠道和来源" :map="{text:'name',value:'name'}"
|
||||
@change="bindCusFromChange"></uni-data-picker>
|
||||
</uni-forms-item>
|
||||
<uni-forms-item label="收款状态">
|
||||
<picker @change="bindpayStatusChange" :value="payStatusIndex" :range="payStatusList">
|
||||
<view class="uni-input">{{payStatusList[payStatusIndex]}}</view>
|
||||
</picker>
|
||||
</uni-forms-item>
|
||||
</uni-forms>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '../../utils/request';
|
||||
import {
|
||||
formatDateTimeToMinute,
|
||||
getDictTextByCodeAndValue,
|
||||
getDictByCode,
|
||||
getDateRange,
|
||||
toPickerData,
|
||||
handleTree
|
||||
} from '@/utils/utils.js';
|
||||
import {
|
||||
checkPermi,
|
||||
checkRole
|
||||
} from "@/utils/permission"; // 权限判断函数
|
||||
import {
|
||||
getToken,
|
||||
getUserInfo,
|
||||
getStrData,
|
||||
getTenantId,
|
||||
setJSONData,
|
||||
getJSONData,
|
||||
getStorageWithExpiry,
|
||||
setStorageWithExpiry
|
||||
} from '@/utils/auth'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
data: undefined,
|
||||
queryParams: {
|
||||
searchTimeArray: [],
|
||||
selectType: 'all',
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
search: null
|
||||
},
|
||||
title: '',
|
||||
timeTypeArray: [{
|
||||
label: '进场时间',
|
||||
value: 'create'
|
||||
}, {
|
||||
label: '结算时间',
|
||||
value: 'settlement'
|
||||
}, ],
|
||||
timeTypeIndex: 1,
|
||||
total: 0,
|
||||
current: 0,
|
||||
// 工种选中下标
|
||||
workTypeIndex: 0,
|
||||
// 维修项目选中下标
|
||||
repairTypeIndex: 0,
|
||||
//维修项目可选值
|
||||
repairTypeList: ['按维修类别'],
|
||||
//维修项目可选值--值
|
||||
repairTypeValueList: [''],
|
||||
//工种可选值
|
||||
workeTypeList: ['按工种类型'],
|
||||
//工种可选值--值
|
||||
workeTypeValueList: [''],
|
||||
//客户来源可选值
|
||||
cusFromList: [
|
||||
['按客户来源'],
|
||||
],
|
||||
//客户来源可选值---值
|
||||
cusFromValueList: [''],
|
||||
// 客户来源选中下标
|
||||
cusFromIndex: [0, 0],
|
||||
//工单状态可选值
|
||||
ticketsStatusList: ['按工单状态', '进厂', '维修中', '已竣工', '已交车', '未结算', '在厂'],
|
||||
//工单状态可选值--值
|
||||
ticketsStatusValueList: ['', 'jinchang', 'weixiuzhong', 'yijungong', 'yijiaoche', 'weijiesuan',
|
||||
'zaichang'
|
||||
],
|
||||
//工单状态选中下标
|
||||
ticketsStatusIndex: 0,
|
||||
//支付状态可选值
|
||||
payStatusList: ['按支付状态', '应收款', '已收款', '待收款'],
|
||||
//支付状态可选值--值
|
||||
payStatusValueList: ['', 'receivable', 'receivedAmount', 'pendingAmount'],
|
||||
//支付状态选中下标
|
||||
payStatusIndex: 0,
|
||||
//渠道可选值
|
||||
busiList: ['按业务渠道'],
|
||||
//渠道可选值--值
|
||||
busiValueList: [''],
|
||||
//渠道选中下标
|
||||
busiIndex: 0,
|
||||
safeLeft: 0,
|
||||
dictData: undefined,
|
||||
statisticsInfo: {},
|
||||
tapIndex: 0,
|
||||
tapList: [{
|
||||
label: "本日",
|
||||
value: "day",
|
||||
},
|
||||
{
|
||||
label: "本月",
|
||||
value: "month",
|
||||
},
|
||||
{
|
||||
label: "全部",
|
||||
value: "all",
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
laborPartsMoney() {
|
||||
return this.statisticsInfo && this.statisticsInfo.totalLaborPartsMoney ? this.statisticsInfo
|
||||
.totalLaborPartsMoney : 0
|
||||
},
|
||||
totalProfit() {
|
||||
return this.statisticsInfo && this.statisticsInfo.totalProfit ? this.statisticsInfo.totalProfit : 0
|
||||
},
|
||||
profitRateWithLabor() {
|
||||
if (this.statisticsInfo && this.statisticsInfo.profitRateWithLabor != null && !isNaN(this.statisticsInfo
|
||||
.profitRateWithLabor)) {
|
||||
return (this.statisticsInfo.profitRateWithLabor * 100).toFixed(2)
|
||||
}
|
||||
return '0.00'
|
||||
},
|
||||
profitRateWithoutLabor() {
|
||||
if (this.statisticsInfo && this.statisticsInfo.profitRateWithoutLabor != null && !isNaN(this.statisticsInfo
|
||||
.profitRateWithoutLabor)) {
|
||||
return (this.statisticsInfo.profitRateWithoutLabor * 100).toFixed(2)
|
||||
}
|
||||
return '0.00'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
repairTypeIndex(newval) {
|
||||
this.initData()
|
||||
},
|
||||
workTypeIndex(newval) {
|
||||
this.initData()
|
||||
},
|
||||
ticketsStatusIndex(newval) {
|
||||
this.initData()
|
||||
},
|
||||
workTypeIndex(newval) {
|
||||
this.initData()
|
||||
},
|
||||
busiIndex(newval) {
|
||||
this.initData()
|
||||
},
|
||||
payStatusIndex(newval) {
|
||||
this.initData()
|
||||
},
|
||||
},
|
||||
onResize() {
|
||||
console.log('执行了刷新');
|
||||
},
|
||||
methods: {
|
||||
checkPermi,
|
||||
checkRole,
|
||||
formatDateTimeToMinute,
|
||||
getDictTextByCodeAndValue,
|
||||
goBack() {
|
||||
// setTimeout(() => {
|
||||
uni.redirectTo({
|
||||
url: '/pages/white/white'
|
||||
});
|
||||
// }, 300)
|
||||
},
|
||||
async initData() {
|
||||
await this.getStatistics();
|
||||
this.queryParams.pageNo = 1;
|
||||
await this.getList()
|
||||
},
|
||||
setDictItem(dictCode, item) {
|
||||
if ("repair_type" == dictCode) {
|
||||
//维修项目
|
||||
this.repairTypeList.push(item.label)
|
||||
this.repairTypeValueList.push(item.value)
|
||||
} else if ("cus_data_from" == dictCode) {
|
||||
//客户来源
|
||||
this.cusFromList.push(item.label)
|
||||
this.cusFromValueList.push(item.value)
|
||||
} else if ("repair_tickets_status" == dictCode) {
|
||||
//工单状态
|
||||
this.ticketsStatusList.push(item.label)
|
||||
this.ticketsStatusValueList.push(item.value)
|
||||
} else if ("repair_work_type" == dictCode) {
|
||||
//工单状态
|
||||
this.workeTypeList.push(item.label)
|
||||
this.workeTypeValueList.push(item.value)
|
||||
}
|
||||
},
|
||||
screening() {
|
||||
this.$refs.popup.open()
|
||||
},
|
||||
/**
|
||||
* 查2个数据字典备用---客户注册方式-cus_data_from、维修业务分类-repair_type
|
||||
*/
|
||||
initDict(dictCode) {
|
||||
let dictArray = getStorageWithExpiry(dictCode);
|
||||
if (null == dictArray || undefined == dictArray) {
|
||||
request({
|
||||
url: '/admin-api/system/dict-data/type',
|
||||
method: 'get',
|
||||
params: {
|
||||
type: dictCode
|
||||
}
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
setStorageWithExpiry(dictCode, res.data, 3600)
|
||||
this.$nextTick(() => {
|
||||
res.data.map(item => {
|
||||
this.setDictItem(dictCode, item)
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$nextTick(() => {
|
||||
dictArray.map(item => {
|
||||
this.setDictItem(dictCode, item)
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 切换维修项目类型
|
||||
*/
|
||||
bindRepairTypeChange(e) {
|
||||
this.repairTypeIndex = e.detail.value
|
||||
// this.onRefresherrefresh()
|
||||
},
|
||||
/**
|
||||
* 切换维修项目类型
|
||||
*/
|
||||
bindBusiChange(e) {
|
||||
this.busiIndex = e.detail.value
|
||||
console.log('选择的渠道', this.busiValueList[e.detail.value]);
|
||||
// this.onRefresherrefresh()
|
||||
},
|
||||
/**
|
||||
* 切换客户来源
|
||||
*/
|
||||
bindCusFromChange(e) {
|
||||
this.initData()
|
||||
// this.onRefresherrefresh()
|
||||
},
|
||||
/**
|
||||
* 切换工单状态
|
||||
*/
|
||||
bindTicketsStatusChange(e) {
|
||||
this.ticketsStatusIndex = e.detail.value
|
||||
// this.onRefresherrefresh()
|
||||
},
|
||||
/**
|
||||
* 切换工单状态
|
||||
*/
|
||||
bindpayStatusChange(e) {
|
||||
this.payStatusIndex = e.detail.value
|
||||
// this.onRefresherrefresh()
|
||||
},
|
||||
/**
|
||||
* 切换工种类型
|
||||
*/
|
||||
bindWorkTypeChange(e) {
|
||||
this.workTypeIndex = e.detail.value
|
||||
// this.onRefresherrefresh()
|
||||
},
|
||||
bindTimeTypeChange(e) {
|
||||
console.log(e);
|
||||
this.timeTypeIndex = e.detail.value
|
||||
|
||||
this.queryParams.timeType = this.timeTypeArray[e.detail.value].value
|
||||
this.initData()
|
||||
// this.onRefresherrefresh()
|
||||
},
|
||||
async getDict() {
|
||||
const list = await getDictByCode('repair_pay_status')
|
||||
this.dictData = list?.reduce((map, item) => {
|
||||
map[item.value] = item.label
|
||||
return map
|
||||
}, {}) ?? {} // 如果 list 为空或 reduce 返回 undefined,则使用空对象
|
||||
console.log('dict', this.dictData)
|
||||
},
|
||||
slectRange(index) {
|
||||
this.selected = index;
|
||||
console.log(index, this.selected);
|
||||
const {
|
||||
value
|
||||
} = this.tapList[index];
|
||||
console.log(value);
|
||||
this.queryParams.searchTimeArray = getDateRange(value);
|
||||
},
|
||||
async tapIcon(index) {
|
||||
this.tapIndex = index
|
||||
await this.slectRange(index)
|
||||
this.queryParams.pageNo = 1
|
||||
await this.initData()
|
||||
},
|
||||
setCurrentMonthRange() {
|
||||
// 直接使用 Date 对象
|
||||
const now = new Date();
|
||||
|
||||
// 创建月初的 Date 对象
|
||||
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
|
||||
this.queryParams.searchTimeArray = [
|
||||
this.formatDate(now), // 月初
|
||||
this.formatDate(now), // 今天
|
||||
];
|
||||
},
|
||||
/**
|
||||
* 获取业务来源和渠道
|
||||
*/
|
||||
queryBusiAndCus() {
|
||||
request({
|
||||
url: `/admin-api/business/list`,
|
||||
method: 'GET',
|
||||
params: {
|
||||
systemCode: 'repair'
|
||||
}
|
||||
}).then(res => {
|
||||
//过滤出pid为0的
|
||||
this.busiList.push(
|
||||
...res.data
|
||||
.filter(item => item.pid === 0)
|
||||
.map(item => item.name)
|
||||
);
|
||||
//过滤出pid为0的
|
||||
this.busiValueList.push(
|
||||
...res.data
|
||||
.filter(item => item.pid === 0)
|
||||
.map(item => item.name)
|
||||
);
|
||||
|
||||
this.cusFromList = handleTree(res.data, 'id', 'pid')
|
||||
})
|
||||
},
|
||||
formatDate(d) {
|
||||
// 添加类型检查,确保 d 是 Date 对象
|
||||
if (!(d instanceof Date)) {
|
||||
console.error("formatDate() 期望接收 Date 对象,但收到:", d);
|
||||
d = new Date(d); // 尝试转换为 Date 对象
|
||||
if (isNaN(d.getTime())) {
|
||||
// 检查是否有效日期
|
||||
d = new Date(); // 如果转换失败,使用当前日期
|
||||
}
|
||||
}
|
||||
return `${d.getFullYear()}-${this.pad(d.getMonth() + 1)}-${this.pad(
|
||||
d.getDate()
|
||||
)}`;
|
||||
},
|
||||
// 补零:1 → 01
|
||||
pad(n) {
|
||||
return n.toString().padStart(2, "0");
|
||||
},
|
||||
getList() {
|
||||
let paramsObj = {
|
||||
repairType: this.repairTypeValueList[this.repairTypeIndex],
|
||||
workType: this.workeTypeValueList[this.workTypeIndex],
|
||||
ticketsStatus: this.ticketsStatusValueList[this.ticketsStatusIndex],
|
||||
busiFrom: this.busiValueList[this.busiIndex],
|
||||
payStatus: this.payStatusValueList[this.payStatusIndex],
|
||||
// timeType: 'settlement',
|
||||
...this.queryParams
|
||||
}
|
||||
|
||||
request({
|
||||
url: `/admin-api/repair/tickets/pageType`,
|
||||
params: paramsObj
|
||||
}).then(res => {
|
||||
this.list = res.data.records
|
||||
this.total = res.data.total
|
||||
this.current = res.data.current
|
||||
})
|
||||
},
|
||||
onPageChange(e) {
|
||||
this.queryParams.pageNo = e.current
|
||||
this.getList()
|
||||
},
|
||||
goWorkDetail(data) {
|
||||
console.log('执行');
|
||||
// 退出时恢复自动(或者你项目里默认的方向)
|
||||
// #ifdef APP-PLUS
|
||||
plus.screen.lockOrientation('portrait-primary'); //锁死屏幕方向为竖屏
|
||||
plus.navigator.setFullscreen(false);
|
||||
// #endif
|
||||
const innerUrl = `/pages-order/orderDetail/orderDetail?id=${data.id}&isDetail=1`
|
||||
const url = `/pages-business/white/newWhite?url=${encodeURIComponent(innerUrl)}`
|
||||
setTimeout(() => {
|
||||
uni.redirectTo({
|
||||
url: innerUrl
|
||||
})
|
||||
}, 1000); // 300毫秒延时,可以根据需要调整
|
||||
},
|
||||
getStatistics() {
|
||||
let paramsObj = {
|
||||
repairType: this.repairTypeValueList[this.repairTypeIndex],
|
||||
workType: this.workeTypeValueList[this.workTypeIndex],
|
||||
ticketsStatus: this.ticketsStatusValueList[this.ticketsStatusIndex],
|
||||
busiFrom: this.busiValueList[this.busiIndex],
|
||||
...this.queryParams
|
||||
}
|
||||
request({
|
||||
url: '/admin-api/repair/tickets/getStatistics',
|
||||
params: paramsObj
|
||||
}).then(res => {
|
||||
this.statisticsInfo = res.data
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 重置请求参数
|
||||
*/
|
||||
resetQueryParams() {
|
||||
this.queryParams.pageNo = 1
|
||||
this.queryParams.pageSize = 10
|
||||
this.queryParams.search = null
|
||||
this.queryParams.cusFrom = null
|
||||
this.queryParams.ticketNo = null
|
||||
|
||||
this.repairTypeIndex = 0
|
||||
this.workTypeIndex = 0
|
||||
this.ticketsStatusIndex = 0
|
||||
this.busiIndex = 0
|
||||
this.payStatusIndex = 0
|
||||
}
|
||||
},
|
||||
//页面显示时切换为横屏配置
|
||||
async onLoad(options) {
|
||||
await this.setCurrentMonthRange()
|
||||
await this.getDict()
|
||||
await this.initDict("repair_type")
|
||||
await this.initDict("repair_work_type")
|
||||
if (options.selectType) {
|
||||
this.ticketsStatusIndex = this.ticketsStatusValueList.indexOf(options.selectType);
|
||||
}
|
||||
if (options.repairType) {
|
||||
this.repairTypeIndex = this.repairTypeValueList.indexOf(options.repairType);
|
||||
}
|
||||
if (options.payStatus) {
|
||||
this.payStatusIndex = this.payStatusValueList.indexOf(options.payStatus);
|
||||
}
|
||||
this.initData()
|
||||
this.queryBusiAndCus()
|
||||
// #ifdef APP-PLUS
|
||||
uni.showLoading({
|
||||
title: "加载中..."
|
||||
})
|
||||
setTimeout(() => {
|
||||
plus.screen.lockOrientation('default');
|
||||
uni.hideLoading();
|
||||
}, 1200)
|
||||
// #endif
|
||||
},
|
||||
//页面卸载时切换为竖屏配置
|
||||
onUnload() {
|
||||
// // 退出时恢复自动(或者你项目里默认的方向)
|
||||
// #ifdef APP-PLUS
|
||||
plus.screen.lockOrientation('portrait-primary'); //锁死屏幕方向为竖屏
|
||||
plus.navigator.setFullscreen(false);
|
||||
// #endif
|
||||
},
|
||||
// 监听页面返回
|
||||
onBackPress() {
|
||||
console.log('执行跳转');
|
||||
// 跳转至空白页
|
||||
uni.redirectTo({
|
||||
url: '/pages/white/white'
|
||||
});
|
||||
return true;
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: white;
|
||||
padding-left: env(safe-area-inset-left);
|
||||
}
|
||||
|
||||
/* 顶部背景和标题 */
|
||||
.header {
|
||||
display: flex;
|
||||
position: relative;
|
||||
height: 100rpx;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 20rpx 40rpx;
|
||||
padding-top: var(--status-bar-height); //给组件加个上边距
|
||||
}
|
||||
|
||||
.bg-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
/* z-index: -1; */
|
||||
}
|
||||
|
||||
.title {
|
||||
text-align: center;
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
line-height: 100rpx;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* 表格 */
|
||||
.table {
|
||||
margin: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.table-row {
|
||||
/* flex-direction: row;
|
||||
display: flex; */
|
||||
}
|
||||
|
||||
.table-header {
|
||||
background-color: #f2f6ff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.table-cell {
|
||||
flex: 1;
|
||||
padding: 20rpx;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.row-bg {
|
||||
background-color: #f9fbff;
|
||||
}
|
||||
|
||||
.status {
|
||||
color: #d4a017;
|
||||
/* 金色 */
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 选项卡样式 */
|
||||
.tabs {
|
||||
display: flex;
|
||||
margin-bottom: 30rpx;
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.cont_time {
|
||||
background: #F1F4F7;
|
||||
border-radius: 36rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0px 30rpx;
|
||||
|
||||
width: 386rpx;
|
||||
height: 56rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 36rpx;
|
||||
}
|
||||
|
||||
.cont_size {
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #686C7A;
|
||||
}
|
||||
|
||||
.tab {
|
||||
margin-right: 40rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
padding: 10rpx 0;
|
||||
|
||||
width: 56rpx;
|
||||
height: 28rpx;
|
||||
font-family: SourceHanSansCN, SourceHanSansCN;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #707677;
|
||||
line-height: 42rpx;
|
||||
text-align: right;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
color: #007AFF;
|
||||
font-weight: bold;
|
||||
|
||||
width: 56rpx;
|
||||
height: 28rpx;
|
||||
font-family: SourceHanSansCN, SourceHanSansCN;
|
||||
font-weight: bold;
|
||||
font-size: 28rpx;
|
||||
color: #292D2E;
|
||||
line-height: 42rpx;
|
||||
text-align: right;
|
||||
font-style: normal;
|
||||
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.tap_img {
|
||||
height: 3px;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
|
||||
image {
|
||||
width: 34rpx;
|
||||
height: 12rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.content_top {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-left: 30rpx;
|
||||
align-items: center;
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.census {
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
font-weight: bold;
|
||||
font-size: 30rpx;
|
||||
/* margin: 1rem 1rem 1rem 0; */
|
||||
}
|
||||
|
||||
.census>span {
|
||||
padding-left: 3rem;
|
||||
}
|
||||
|
||||
.credited {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.notCredited {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.onlinePay {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.cashPay {
|
||||
color: goldenrod;
|
||||
}
|
||||
|
||||
.signedPay {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.content_right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.line {
|
||||
width: 2rpx;
|
||||
height: 60rpx;
|
||||
background-color: #DDDDDD;
|
||||
}
|
||||
|
||||
.tap_icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
|
||||
.search {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.popup {
|
||||
padding-top: var(--status-bar-height);
|
||||
width: 700rpx;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
padding: 20rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.border_ {
|
||||
border: 1px solid #0357FF;
|
||||
border-radius: 50rpx;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.body-top-tab {
|
||||
background: white;
|
||||
display: flex;
|
||||
font-size: 30rpx;
|
||||
padding: 5rpx 0;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.body-top-tab .line {
|
||||
width: 2rpx;
|
||||
height: 60rpx;
|
||||
background-color: #DDDDDD;
|
||||
}
|
||||
|
||||
.body-top-tab-item {
|
||||
width: 100%;
|
||||
padding: 20rpx 0;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.body-top-tab-item .label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.reset {
|
||||
color: #165DFF;
|
||||
padding: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* 横屏适配 */
|
||||
@media (orientation: landscape) {
|
||||
.popup {
|
||||
width: 60vw;
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
max-height: 100vh;
|
||||
}
|
||||
}
|
||||
</style>
|
555
pages-detail/detail/detail.vue
Normal file
@ -0,0 +1,555 @@
|
||||
<template>
|
||||
<view class="detail-container">
|
||||
<view class="top">
|
||||
<view class="navbar">
|
||||
<uni-icons type="left" color="#1f2d3d" size="22" @click="goBack" />
|
||||
<text class="navbar-title">详情页</text>
|
||||
</view>
|
||||
|
||||
<view class="header">
|
||||
<!-- 选项卡 -->
|
||||
<view class="tabs">
|
||||
<view class="tab" :class="{'active':currentTab == index}" v-for="(item,index) in tapList"
|
||||
:key="index" @click="switchTab(index)">
|
||||
<view class="">{{item.label || "无"}}</view>
|
||||
<view class="tap_img" style="display: block;" v-show="currentTab == index">
|
||||
<image src="/static/images/icon_tap.png" mode="widthFix" class="tap_icon"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="">
|
||||
<uni-datetime-picker v-model="queryParams.dateRange" type="daterange" @change="loadData()"
|
||||
rangeSeparator="至" class="">
|
||||
<view class="cont_time">
|
||||
<view class="cont_size">{{queryParams.dateRange[0]}}</view>
|
||||
<view class="bule_size"></view>
|
||||
<view class="cont_size">{{queryParams.dateRange[1]}}</view>
|
||||
<view class=""> <u-icon name="arrow-down-fill" color="#0357FF" size="12"></u-icon></view>
|
||||
</view>
|
||||
</uni-datetime-picker>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="content">
|
||||
<view class="section-list">
|
||||
<view class="section-card" v-for="(sKey, idx) in statsData" :key="idx">
|
||||
<view class="section-header" @click="goList(sKey.selectType)">
|
||||
<view class="section-header-left">
|
||||
<view class="section-tag">{{ sKey.name }}</view>
|
||||
<view class="section-total">{{ sKey.total }}台次</view>
|
||||
</view>
|
||||
<view class="section-header-right">
|
||||
<image src="../images/small.png" mode="widthFix" class="tap_icon" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="section-body">
|
||||
<view class="kv" v-for="(item, i) in sKey.children" :key="i"
|
||||
@click="goList(sKey.selectType,item.repairType)">
|
||||
<view class="kv-number">{{ item.count }}</view>
|
||||
<view class="kv-label">{{ dictData[item.repairType] }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="finance" v-if="checkPermi(['repair:tick:profit'])">
|
||||
<view class="fin-card receivable" @click.self="goListByPayStatus('receivable')">
|
||||
<view class="fin-top">
|
||||
<text class="fin-title">应收款</text>
|
||||
<uni-icons :type="financeVisibility.receivable ? 'eye' : 'eye-slash'" color="#7aa6ff" size="20"
|
||||
@click="toggleFinance('receivable')" />
|
||||
</view>
|
||||
<!-- 已收款金额 -->
|
||||
<text
|
||||
class="fin-amount">{{ financeVisibility.receivable ? formatCurrency(otherInfo.receivableAmount || 0) : '*****' }}</text>
|
||||
<view class="fin-bottom">
|
||||
<view class="fin-count">{{otherInfo.receivableCount}}台次</view>
|
||||
<image src="../images/money_one.png" mode="widthFix" class="tap_icon"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="fin-card collected" @click.self="goListByPayStatus('receivedAmount')">
|
||||
<view class="fin-top">
|
||||
<text class="fin-title">已收款</text>
|
||||
<uni-icons :type="financeVisibility.collected ? 'eye' : 'eye-slash'" color="#a896ff" size="20"
|
||||
@click="toggleFinance('collected')" />
|
||||
</view>
|
||||
<text
|
||||
class="fin-amount">{{ financeVisibility.collected ? formatCurrency(otherInfo.receivedAmount) : '*****' }}</text>
|
||||
<view class="fin-bottom">
|
||||
<view class="fin-count">{{otherInfo.receivedCount}}台次</view>
|
||||
<image src="../images/money_two.png" mode="widthFix" class="tap_icon"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="fin-card pending" @click.self="goListByPayStatus('pendingAmount')">
|
||||
<view class="fin-top">
|
||||
<text class="fin-title">待收款</text>
|
||||
<uni-icons :type="financeVisibility.pending ? 'eye' : 'eye-slash'" color="#ffcf7a" size="20"
|
||||
@click="toggleFinance('pending')" />
|
||||
</view>
|
||||
<text
|
||||
class="fin-amount">{{ financeVisibility.pending ? formatCurrency(otherInfo.pendingAmount) : '*****' }}</text>
|
||||
<view class="fin-bottom">
|
||||
<view class="fin-count">{{otherInfo.pendingCount}}台次</view>
|
||||
<image src="../images/money_three.png" mode="widthFix" class="tap_icon"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '@/utils/request';
|
||||
import {
|
||||
formatCurrency,
|
||||
getDictByCode,
|
||||
getDateRange
|
||||
} from '@/utils/utils';
|
||||
import {
|
||||
checkPermi,
|
||||
checkRole
|
||||
} from "@/utils/permission"; // 权限判断函数
|
||||
|
||||
export default {
|
||||
name: 'DetailPage',
|
||||
data() {
|
||||
return {
|
||||
currentTab: 0,
|
||||
queryParams: {
|
||||
dateRange: [],
|
||||
},
|
||||
sectionOrder: ['orders', 'repairing', 'completed', 'settled', 'unsettled', 'delivered', 'inFactory'],
|
||||
sectionTitle: {
|
||||
orders: '订单(进厂)数',
|
||||
repairing: '维修中',
|
||||
completed: '已竣工',
|
||||
settled: '竣工已结算',
|
||||
unsettled: '竣工未结算',
|
||||
delivered: '已交车',
|
||||
inFactory: '在厂数'
|
||||
},
|
||||
tapList: [{
|
||||
label: "本日",
|
||||
value: "day",
|
||||
},
|
||||
{
|
||||
label: "本月",
|
||||
value: "month",
|
||||
},
|
||||
{
|
||||
label: "全部",
|
||||
value: "all",
|
||||
},
|
||||
],
|
||||
statsData: {},
|
||||
financeVisibility: {
|
||||
receivable: false,
|
||||
collected: false,
|
||||
pending: false
|
||||
},
|
||||
dictData: undefined,
|
||||
otherInfo: {}
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
await this.setCurrentMonthRange()
|
||||
this.getDict()
|
||||
this.loadFinanceVisibility() // 从缓存加载显示设置
|
||||
this.loadData();
|
||||
},
|
||||
methods: {
|
||||
checkPermi,
|
||||
checkRole,
|
||||
async switchTab(tab) {
|
||||
if (this.currentTab !== tab) {
|
||||
this.currentTab = tab;
|
||||
|
||||
await this.slectRange(tab)
|
||||
}
|
||||
},
|
||||
slectRange(index) {
|
||||
this.selected = index;
|
||||
console.log(index, this.selected);
|
||||
const {
|
||||
value
|
||||
} = this.tapList[index];
|
||||
console.log(value);
|
||||
this.queryParams.dateRange = getDateRange(value);
|
||||
},
|
||||
showDatePicker() {
|
||||
console.log('show date picker');
|
||||
},
|
||||
// 从本地缓存加载显示设置
|
||||
loadFinanceVisibility() {
|
||||
try {
|
||||
const savedVisibility = uni.getStorageSync('financeVisibility');
|
||||
if (savedVisibility) {
|
||||
this.financeVisibility = savedVisibility;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to load finance visibility from storage:', e);
|
||||
}
|
||||
},
|
||||
|
||||
// 切换财务信息显示/隐藏并保存到缓存
|
||||
toggleFinance(key) {
|
||||
this.financeVisibility[key] = !this.financeVisibility[key];
|
||||
|
||||
// 保存到本地缓存
|
||||
try {
|
||||
uni.setStorageSync('financeVisibility', this.financeVisibility);
|
||||
} catch (e) {
|
||||
console.error('Failed to save finance visibility to storage:', e);
|
||||
}
|
||||
},
|
||||
async getDict() {
|
||||
const list = await getDictByCode('repair_type')
|
||||
this.dictData = list?.reduce((map, item) => {
|
||||
map[item.value] = item.label
|
||||
return map
|
||||
}, {}) ?? {} // 如果 list 为空或 reduce 返回 undefined,则使用空对象
|
||||
console.log('dict', this.dictData)
|
||||
},
|
||||
/**
|
||||
* 列表
|
||||
*/
|
||||
goList(selectType, repairType) {
|
||||
if (repairType) {
|
||||
uni.navigateTo({
|
||||
url: `/pages-business/statistics/statistics?selectType=${selectType}&repairType=${repairType}`
|
||||
})
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: `/pages-business/statistics/statistics?selectType=${selectType}`
|
||||
})
|
||||
}
|
||||
},
|
||||
goListByPayStatus(payStatus) {
|
||||
uni.navigateTo({
|
||||
url: `/pages-business/statistics/statistics?payStatus=${payStatus}`
|
||||
})
|
||||
},
|
||||
loadData() {
|
||||
request({
|
||||
url: '/admin-api/repair/tickets/getBossNumStatistics',
|
||||
method: 'get',
|
||||
params: this.queryParams
|
||||
}).then(res => {
|
||||
if (res.code === 200 && res.data) {
|
||||
this.statsData = res.data.stats;
|
||||
this.otherInfo = res.data
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('Failed to load stats data:', error);
|
||||
});
|
||||
},
|
||||
formatCurrency(amount) {
|
||||
return formatCurrency(amount);
|
||||
},
|
||||
// toggleFinance(key) {
|
||||
// this.financeVisibility[key] = !this.financeVisibility[key];
|
||||
// },
|
||||
goBack() {
|
||||
uni.navigateBack();
|
||||
},
|
||||
setCurrentMonthRange() {
|
||||
// 直接使用 Date 对象
|
||||
const now = new Date();
|
||||
|
||||
// 创建月初的 Date 对象
|
||||
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
|
||||
this.queryParams.dateRange = [
|
||||
this.formatDate(now), // 月初
|
||||
this.formatDate(now), // 今天
|
||||
];
|
||||
},
|
||||
formatDate(d) {
|
||||
// 添加类型检查,确保 d 是 Date 对象
|
||||
if (!(d instanceof Date)) {
|
||||
console.error("formatDate() 期望接收 Date 对象,但收到:", d);
|
||||
d = new Date(d); // 尝试转换为 Date 对象
|
||||
if (isNaN(d.getTime())) {
|
||||
// 检查是否有效日期
|
||||
d = new Date(); // 如果转换失败,使用当前日期
|
||||
}
|
||||
}
|
||||
return `${d.getFullYear()}-${this.pad(d.getMonth() + 1)}-${this.pad(
|
||||
d.getDate()
|
||||
)}`;
|
||||
},
|
||||
// 补零:1 → 01
|
||||
pad(n) {
|
||||
return n.toString().padStart(2, "0");
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
currentTab() {
|
||||
this.loadData();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.detail-container {
|
||||
/* background: #f2f6ff; */
|
||||
min-height: 100vh;
|
||||
padding-bottom: 24rpx;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
height: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 24rpx;
|
||||
}
|
||||
|
||||
.top {
|
||||
background-image: url('/static/images/table_header.png');
|
||||
padding-top: var(--status-bar-height); //给组件加个上边距
|
||||
}
|
||||
|
||||
.navbar-title {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
color: #1f2d3d;
|
||||
font-weight: 600;
|
||||
font-size: 32rpx;
|
||||
margin-right: 44rpx;
|
||||
}
|
||||
|
||||
.header {
|
||||
margin: 0 24rpx 24rpx;
|
||||
/* background: linear-gradient(180deg, #e8f1ff 0%, #f5f8ff 100%); */
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
/* box-shadow: 0 8rpx 24rpx rgba(88, 131, 255, 0.12); */
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
gap: 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.tab {
|
||||
font-size: 28rpx;
|
||||
color: #7f8fa4;
|
||||
position: relative;
|
||||
padding-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
color: #2a6cff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tab.active:after {
|
||||
/* content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 48rpx;
|
||||
height: 6rpx;
|
||||
background: #2a6cff;
|
||||
border-radius: 6rpx; */
|
||||
}
|
||||
|
||||
.date-range {
|
||||
background: #ffffff;
|
||||
border-radius: 12rpx;
|
||||
padding: 18rpx 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: #5f6b7a;
|
||||
box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.date-text {
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.section-list {
|
||||
padding: 0 24rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.section-card {
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 8rpx 28rpx rgba(31, 45, 61, 0.06);
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16rpx 8rpx;
|
||||
background: linear-gradient(180deg, #EDF8FF 0%, #FBFEFF 100%);
|
||||
}
|
||||
|
||||
.section-header-left {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.section-header-right {
|
||||
image {
|
||||
height: 30rpx;
|
||||
width: 30rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.section-tag {
|
||||
background-image: url('../images/list_title.png');
|
||||
color: #2a6cff;
|
||||
font-size: 26rpx;
|
||||
padding: 10rpx 18rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.section-total {
|
||||
padding: 10rpx 18rpx;
|
||||
font-size: 28rpx;
|
||||
color: #144B7E;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.section-body {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 16rpx;
|
||||
padding: 8rpx;
|
||||
}
|
||||
|
||||
.kv {
|
||||
border-radius: 12rpx;
|
||||
padding: 18rpx 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.kv-number {
|
||||
color: #1f2d3d;
|
||||
font-weight: 700;
|
||||
font-size: 30rpx;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.kv-label {
|
||||
color: #7f8fa4;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
.finance {
|
||||
padding: 16rpx 24rpx 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.fin-card {
|
||||
border-radius: 16rpx;
|
||||
padding: 18rpx;
|
||||
color: #1f2d3d;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10rpx;
|
||||
box-shadow: 0 10rpx 28rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.fin-card.receivable {
|
||||
background: linear-gradient(180deg, #eaf3ff, #f3f8ff);
|
||||
}
|
||||
|
||||
.fin-card.collected {
|
||||
background: linear-gradient(180deg, #f1ecff, #f7f4ff);
|
||||
}
|
||||
|
||||
.fin-card.pending {
|
||||
background: linear-gradient(180deg, #fff3df, #fff8ea);
|
||||
}
|
||||
|
||||
.tap_img {
|
||||
height: 3px;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
|
||||
image {
|
||||
width: 34rpx;
|
||||
height: 12rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.fin-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.fin-title {
|
||||
color: #7f8fa4;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
.fin-amount {
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
letter-spacing: 1rpx;
|
||||
}
|
||||
|
||||
.fin-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: #7f8fa4;
|
||||
font-size: 22rpx;
|
||||
|
||||
image {
|
||||
height: 30rpx;
|
||||
width: 30rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.cont_time {
|
||||
background: #F1F4F7;
|
||||
border-radius: 36rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0px 30rpx;
|
||||
|
||||
width: 386rpx;
|
||||
height: 56rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 36rpx;
|
||||
}
|
||||
|
||||
.cont_size {
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #686C7A;
|
||||
}
|
||||
|
||||
.tap_icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
</style>
|
BIN
pages-detail/images/list_title.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
pages-detail/images/money_one.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
pages-detail/images/money_three.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
pages-detail/images/money_two.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
pages-detail/images/small.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
1589
pages-home/home/home1.vue
Normal file
568
pages-home/home/index1.vue
Normal file
@ -0,0 +1,568 @@
|
||||
<template>
|
||||
<view class="content_">
|
||||
<view class="topt_">
|
||||
<view class="db_">
|
||||
<view class="ds_">
|
||||
<view class="user_img">
|
||||
<image src="/static/icons/avatar.png" mode=""></image>
|
||||
<view class="img_bo">蓝安汽修</view>
|
||||
</view>
|
||||
<view class="">
|
||||
<view class="user_name">思利利</view>
|
||||
<view class="user_gly">维修业务管理员</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="top_time">
|
||||
<view class="time_left">2015年08月12日</view>
|
||||
<view class="time_right">星期二</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="jg_">
|
||||
<view class="jg_box">
|
||||
<image src="/static/icons/order-icon3.png" mode=""></image>
|
||||
<view class="">内部管理</view>
|
||||
</view>
|
||||
<view class="jg_box">
|
||||
<image src="/static/icons/order-icon3.png" mode=""></image>
|
||||
<view class="">业务管理</view>
|
||||
</view>
|
||||
<view class="jg_box">
|
||||
<image src="/static/icons/order-icon3.png" mode=""></image>
|
||||
<view class="">数据统计</view>
|
||||
</view>
|
||||
<view class="jg_box">
|
||||
<image src="/static/icons/order-icon3.png" mode=""></image>
|
||||
<view class="">消息通知</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="bo_">
|
||||
<view class="db_">
|
||||
<view class="jg_left">
|
||||
<view class="ds_">
|
||||
<image src="/pages-home/static/waitingReceiveNum.png" mode=""></image>
|
||||
<view class="">待审批工单</view>
|
||||
</view>
|
||||
<view class="">26</view>
|
||||
</view>
|
||||
<view class="jg_right">
|
||||
<view class="ds_">
|
||||
<image src="/pages-home/static/waitingReceiveNum.png" mode=""></image>
|
||||
<view class="">待办工单</view>
|
||||
</view>
|
||||
<view class="">26</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="db_">
|
||||
<view class="three1">
|
||||
<view class="">
|
||||
<view class="t_size">进厂数</view>
|
||||
<view class="t_num">123</view>
|
||||
</view>
|
||||
<image src="/pages-home/static/waitingReceiveNum.png" mode=""></image>
|
||||
</view>
|
||||
<view class="three2">
|
||||
<view class="">
|
||||
<view class="t_size">维修中</view>
|
||||
<view class="t_num">123</view>
|
||||
</view>
|
||||
<image src="/pages-home/static/waitingReceiveNum.png" mode=""></image>
|
||||
</view>
|
||||
<view class="three3">
|
||||
<view class="">
|
||||
<view class="t_size">已竣工</view>
|
||||
<view class="t_num">123</view>
|
||||
</view>
|
||||
<image src="/pages-home/static/waitingReceiveNum.png" mode=""></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="db_c">
|
||||
<view class="ds_">
|
||||
<view class="gang_"></view>
|
||||
<view class="title_">工单列表</view>
|
||||
</view>
|
||||
<view class="ds_h">查看全部</view>
|
||||
</view>
|
||||
<view class="c_box">
|
||||
<view class="db_">
|
||||
<view class="">
|
||||
<view class="size1">川EPY528</view>
|
||||
<view class="size2">东风</view>
|
||||
</view>
|
||||
<view class="">
|
||||
<view class="size3">维修保养</view>
|
||||
<view class="size4">进厂报修项目</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="cont_title">
|
||||
<view class="c_t_title">所有维修项目</view>
|
||||
<view class="c_t_size">轿车二级维护、发动机维修、空调系统检修</view>
|
||||
</view>
|
||||
<view class="end_">
|
||||
<view class="r_buttom">作废</view>
|
||||
<view class="l_buttom">展开</view>
|
||||
<view class="l_buttom">查看详情</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getToken,getUserInfo} from "@/utils/auth";
|
||||
import request from '@/utils/request';
|
||||
let innerAudioContext ='';
|
||||
const keepAlivePlugin = uni.requireNativePlugin('Ba-KeepAlive')
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
// 是否正在播放
|
||||
ifPlay:false,
|
||||
keepLive: {
|
||||
channelId: 'Ba-KeepAlive',
|
||||
channelName: "Ba-KeepAlive",
|
||||
title: "汽修小助手正在运行",
|
||||
content: "汽修小助手正在运行",
|
||||
dataResult: "",
|
||||
type: undefined
|
||||
}
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
// #ifdef APP
|
||||
//保活技术
|
||||
this.register()
|
||||
// #endif
|
||||
if (getToken()) {
|
||||
this.getNoReadNum()
|
||||
//跳转首页
|
||||
//判断是否是仓管,仓管需要跳单独的首页
|
||||
let userInfo = getUserInfo()
|
||||
if (userInfo.roleCodes.includes('repair_warehouse')) {
|
||||
//仓管
|
||||
uni.navigateTo({
|
||||
url: '/pages-warehouse/home/home'
|
||||
})
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: '/pages-home/home/home'
|
||||
})
|
||||
}
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: '/pages/login/login'
|
||||
})
|
||||
}
|
||||
},
|
||||
onShow(){
|
||||
if (getToken()) {
|
||||
//判断是否是仓管,仓管需要跳单独的首页
|
||||
let userInfo = getUserInfo()
|
||||
if (userInfo.roleCodes.includes('repair_warehouse')) {
|
||||
//仓管
|
||||
uni.navigateTo({
|
||||
url: '/pages-warehouse/home/home'
|
||||
})
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: '/pages-home/home/home'
|
||||
})
|
||||
}
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: '/pages/login/login'
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
register() { //注册
|
||||
console.log(keepAlivePlugin, 'keepAlive');
|
||||
keepAlivePlugin.register({
|
||||
channelId: this.keepLive.channelId,
|
||||
channelName: this.keepLive.channelName,
|
||||
title: this.keepLive.title,
|
||||
content: this.keepLive.content,
|
||||
},
|
||||
(res) => {
|
||||
console.log('保活注册', res);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 获取未读消息数量
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async getNoReadNum(){
|
||||
await request({
|
||||
url: "/admin-api/system/notify-message/get-unread-count?systemCode=weixiu",
|
||||
method: "GET"
|
||||
}).then((res) => {
|
||||
if(res.code==200 && res.data>0){
|
||||
this.dianyidain()
|
||||
}
|
||||
})
|
||||
},
|
||||
dianyidain() {
|
||||
if(!this.ifPlay){
|
||||
console.log('执行了,dianyidain');
|
||||
if(innerAudioContext!=""){
|
||||
try {
|
||||
console.log('调用前先销毁');
|
||||
innerAudioContext.stop();
|
||||
innerAudioContext.destroy();
|
||||
innerAudioContext="";
|
||||
}catch (e){
|
||||
console.log('销毁出错');
|
||||
}
|
||||
}
|
||||
innerAudioContext = uni.createInnerAudioContext();
|
||||
this.ifPlay=true
|
||||
// #ifdef APP-PLUS
|
||||
innerAudioContext.src = '../../static/msgV.mp3';
|
||||
// #endif
|
||||
// #ifndef APP-PLUS
|
||||
innerAudioContext.src = 'https://www.nuoyunr.com/lananRsc/rescue/msgV.mp3';
|
||||
// #endif
|
||||
// 设置播放次数和计数器
|
||||
const playCount = 4;
|
||||
let currentCount = 0;
|
||||
// 初次播放
|
||||
innerAudioContext.play();
|
||||
// 震动
|
||||
uni.vibrateLong({
|
||||
success: function () {
|
||||
console.log('success');
|
||||
}
|
||||
});
|
||||
innerAudioContext.onError((err) => {
|
||||
console.error('播放错误', err);
|
||||
this.ifPlay=false
|
||||
innerAudioContext.stop();
|
||||
innerAudioContext.destroy(); // 播放错误后释放实例
|
||||
});
|
||||
// 监听音频播放结束事件
|
||||
innerAudioContext.onEnded(() => {
|
||||
// 播放计数加一
|
||||
currentCount++;
|
||||
// 判断是否达到播放次数上限
|
||||
if (currentCount < playCount) {
|
||||
// 继续播放
|
||||
innerAudioContext.play();
|
||||
// 震动
|
||||
uni.vibrateLong({
|
||||
success: function () {
|
||||
console.log('success');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 播放完成,可以在这里添加额外的逻辑
|
||||
console.log('播放完成');
|
||||
this.ifPlay=false
|
||||
//及时释放资源
|
||||
innerAudioContext.stop();
|
||||
innerAudioContext.destroy();
|
||||
}
|
||||
});
|
||||
}else{
|
||||
console.log('正在播放音频,拒绝播放请求');
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content_{
|
||||
|
||||
}
|
||||
.topt_{
|
||||
width: 100%;
|
||||
height: 408rpx;
|
||||
background: linear-gradient( 180deg, #2D3BFF 0%, #1463FF 100%);
|
||||
border-radius: 0rpx 0rpx 12rpx 12rpx;
|
||||
box-sizing: border-box;
|
||||
padding: 30rpx;
|
||||
padding-top: 96px;
|
||||
}
|
||||
.db_{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.db_c{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 30rpx auto;
|
||||
}
|
||||
.ds_{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.top_time{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.time_left{
|
||||
width: 210rpx;
|
||||
height: 52rpx;
|
||||
background: rgba(255,255,255,0.4);
|
||||
border-radius: 36rpx 0rpx 0rpx 36rpx;
|
||||
background: #7e90fe;
|
||||
color: #fff;
|
||||
}
|
||||
.time_right{
|
||||
background: #fff;
|
||||
color: #214FFF;
|
||||
border-radius: 36rpx 0rpx 0rpx 36rpx;
|
||||
width: 118rpx;
|
||||
height: 52rpx;
|
||||
}
|
||||
.user_gly{
|
||||
font-weight: 400;
|
||||
color: rgba(255,255,255,0.83);
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.user_name{
|
||||
font-weight: bold;
|
||||
font-size: 28rpx;
|
||||
color: #FFFFFF;
|
||||
margin-bottom: 5rpx;
|
||||
}
|
||||
.user_img{
|
||||
position: relative;
|
||||
text-align: center;
|
||||
image{
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
}
|
||||
}
|
||||
.img_bo{
|
||||
width: 116rpx;
|
||||
height: 32rpx;
|
||||
background: linear-gradient( 180deg, #8DB4FF 0%, #3069FF 100%);
|
||||
border-radius: 20rpx;
|
||||
border: 1rpx solid rgba(255,255,255,0.46);
|
||||
font-weight: 500;
|
||||
font-size: 24rpx;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.jg_{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.jg_box{
|
||||
text-align: center;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #FFFFFF;
|
||||
width: 25%;
|
||||
image{
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
}
|
||||
.bo_{
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 30rpx;
|
||||
}
|
||||
.jg_left{
|
||||
width: 356rpx;
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
padding: 30rpx;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
font-size: 28rpx;
|
||||
color: #FFFFFF;
|
||||
background: linear-gradient( 68deg, #6CAFFF 0%, #0059FF 100%);
|
||||
image{
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
margin-right: 15rpx;
|
||||
}
|
||||
}
|
||||
.jg_right{
|
||||
width: 356rpx;
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
padding: 30rpx;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
font-size: 28rpx;
|
||||
color: #FFFFFF;
|
||||
background: linear-gradient( 68deg, #87E2FF 0%, #008BFF 100%);
|
||||
image{
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
margin-right: 15rpx;
|
||||
}
|
||||
}
|
||||
.three1{
|
||||
width: 234rpx;
|
||||
height: 120rpx;
|
||||
background: linear-gradient( 68deg, #EEF5FF 0%, #D7E0FC 100%);
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
padding: 10rpx;
|
||||
padding-left: 30rpx;
|
||||
image{
|
||||
width: 96rpx;
|
||||
height: 92rpx;
|
||||
}
|
||||
}
|
||||
.three2{
|
||||
width: 234rpx;
|
||||
height: 120rpx;
|
||||
background: linear-gradient( 84deg, #E3F2F5 0%, #AFEEF8 100%);
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
padding: 10rpx;
|
||||
padding-left: 30rpx;
|
||||
image{
|
||||
width: 96rpx;
|
||||
height: 92rpx;
|
||||
}
|
||||
}
|
||||
.three3{
|
||||
width: 234rpx;
|
||||
height: 120rpx;
|
||||
background: linear-gradient( 84deg, #E8F2E1 0%, #CCEFDD 100%);
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
padding: 10rpx;
|
||||
padding-left: 30rpx;
|
||||
image{
|
||||
width: 96rpx;
|
||||
height: 92rpx;
|
||||
}
|
||||
}
|
||||
.t_size{
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #284F89;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
.t_num{
|
||||
font-weight: bold;
|
||||
font-size: 28rpx;
|
||||
color: #3E4045;
|
||||
}
|
||||
.gang_{
|
||||
width: 8rpx;
|
||||
height: 40rpx;
|
||||
background: #195AFF;
|
||||
margin-right: 8rpx;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.title_{
|
||||
font-weight: 800;
|
||||
font-size: 28rpx;
|
||||
color: #23252B;
|
||||
}
|
||||
.ds_h{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #9799A1;
|
||||
}
|
||||
.c_box{
|
||||
width: 100%;
|
||||
height: 300rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 8rpx;
|
||||
box-sizing: border-box;
|
||||
padding: 30rpx;
|
||||
margin: 10px auto;
|
||||
}
|
||||
.size1{
|
||||
font-weight: 600;
|
||||
font-size: 28rpx;
|
||||
color: #3B3D41;
|
||||
}
|
||||
.size2{
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #686B71;
|
||||
}
|
||||
.size3{
|
||||
font-weight: 600;
|
||||
font-size: 28rpx;
|
||||
color: #3B3D41;
|
||||
}
|
||||
.size4{
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #176C97;
|
||||
}
|
||||
.cont_title{
|
||||
height: 98rpx;
|
||||
background: #F7F8F9;
|
||||
border-radius: 8rpx;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 10rpx;
|
||||
margin: 10rpx auto;
|
||||
}
|
||||
.c_t_title{
|
||||
font-weight: 400;
|
||||
font-size: 24rpx;
|
||||
color: #176C97;
|
||||
}
|
||||
.c_t_size{
|
||||
font-weight: 600;
|
||||
font-size: 24rpx;
|
||||
color: #3B3D41;
|
||||
}
|
||||
.end_{
|
||||
display: flex;align-items: center;justify-content: end;
|
||||
}
|
||||
.l_buttom{
|
||||
width: 168rpx;
|
||||
height: 48rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 30rpx;
|
||||
border: 2rpx solid #2E90F2;
|
||||
color: #2E90F2;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #2E90F2;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
.r_buttom{
|
||||
width: 168rpx;
|
||||
height: 48rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 30rpx;
|
||||
border: 2rpx solid #F2612E;
|
||||
color: #F2612E;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
</style>
|
158
pages-internal/deviceManagement/deviceManage.vue
Normal file
@ -0,0 +1,158 @@
|
||||
<template>
|
||||
<view class="">
|
||||
<!-- <view class="top-rail"></view>
|
||||
<view class="page-top" :style='{ justifyContent: "center" }'>
|
||||
|
||||
<view class='go-back-page' @click='pageBack'>返回</view>
|
||||
|
||||
<view class="other-title-class">
|
||||
设备管理
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<VNavigationBar style="position: relative;z-index: 99;" homeHeaderPaddingTop="0" backgroundColor="#fff"
|
||||
title-color="#000" title="设备管理"></VNavigationBar>
|
||||
<view class="content">
|
||||
|
||||
<view class="box_">
|
||||
<view class="box_list" v-for="(item, index) in tabList">
|
||||
<view class="" @click="gettap(item)">
|
||||
<image :src=defaultIcon mode=""></image>
|
||||
<!-- <image :src=iconArr[index] mode=""></image> -->
|
||||
<view class="name_">{{ item.categoryName }}</view>
|
||||
<view class="">{{ item.count }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getDictDataByType
|
||||
} from "@/utils/utils";
|
||||
import request from "@/utils/request";
|
||||
|
||||
import VNavigationBar from "@/components/VNavigationBar.vue";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
titles: "设备管理",
|
||||
List: [],
|
||||
show: false,
|
||||
status: 'loading',
|
||||
tabList: [],
|
||||
/* iconArr: ["../../static/internal/s1.png", "../../static/internal/s2.png", "../../static/internal/s3.png",
|
||||
"../../static/internal/s4.png"
|
||||
] */
|
||||
defaultIcon: "../../static/icons/internal/s1.png"
|
||||
}
|
||||
},
|
||||
components: {
|
||||
VNavigationBar
|
||||
},
|
||||
onLoad() {
|
||||
// this.getTab()
|
||||
this.getCount()
|
||||
},
|
||||
methods: {
|
||||
gettap(value) {
|
||||
uni.navigateTo({
|
||||
url: `/pages-internal/deviceManagement/informationManage?value=${value.categoryId}`
|
||||
})
|
||||
},
|
||||
async getTab() {
|
||||
const data = await getDictDataByType("repair_equ_type");
|
||||
this.tabList = [...this.tabList, ...data];
|
||||
},
|
||||
pageBack() {
|
||||
uni.navigateBack({
|
||||
delta: 1 // delta值为1时表示返回的页面层数
|
||||
});
|
||||
},
|
||||
getCount() {
|
||||
const data = request({
|
||||
url: '/admin-api/system/equInfo/queryEquipmentCountByPackageId',
|
||||
method: 'get',
|
||||
params: {
|
||||
servicePackageId: 'weixiu',
|
||||
dictType: 'repair_equ_type'
|
||||
}
|
||||
});
|
||||
this.tabList = data.then(res => {
|
||||
this.tabList = res.data
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped lang="scss">
|
||||
.content {
|
||||
/* background: #F7F8FC;
|
||||
width: 100%;
|
||||
height: calc(100vh - 220rpx);
|
||||
box-sizing: border-box;
|
||||
padding: 30rpx; */
|
||||
// padding-top: 200rpx;
|
||||
background: #F7F8FC;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.box_ {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin-top: 40rpx;
|
||||
}
|
||||
|
||||
.box_list {
|
||||
width: 328rpx;
|
||||
height: 396rpx;
|
||||
background: #fff;
|
||||
border-radius: 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
image {
|
||||
width: 130rpx;
|
||||
height: 130rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.name_ {
|
||||
font-size: 28rpx;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.num_ {
|
||||
font-size: 36rpx;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* .content {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background: #f4f5f6;
|
||||
// background: #55aaff;
|
||||
// height: 100vh;
|
||||
} */
|
||||
|
||||
.top-rail {
|
||||
height: 60rpx;
|
||||
width: 100%;
|
||||
background-color: #054DF3;
|
||||
}
|
||||
</style>
|
580
pages-internal/deviceManagement/informationAdd.vue
Normal file
@ -0,0 +1,580 @@
|
||||
<!-- 发起订单 -->
|
||||
<template>
|
||||
<view class="content">
|
||||
<!-- <view class="top-rail"></view>
|
||||
<view class="c-top" :style='{ justifyContent: "center" }'>
|
||||
<view class="go-back-page" @click="getback()">返回</view>
|
||||
<view class="c-title" v-if="type == 'add'">新增设备</view>
|
||||
<view class="c-title" v-if="type == 'edit'">编辑设备</view>
|
||||
<view class=""></view>
|
||||
</view> -->
|
||||
<!-- <headersVue :titles="pageName" style="position: static !important;">
|
||||
<u-icon name="arrow-left" color="#fff" size="18"></u-icon>
|
||||
</headersVue> -->
|
||||
<VNavigationBar style="position: relative;z-index: 99;" homeHeaderPaddingTop="0" backgroundColor="#fff"
|
||||
title-color="#000" :title="pageName"></VNavigationBar>
|
||||
<view class="dil">
|
||||
<view class="tinput">
|
||||
|
||||
<view class="text1">
|
||||
<text class="hong1">*</text>
|
||||
设备名称
|
||||
</view>
|
||||
<view class="you">
|
||||
<input type="text" placeholder="请输入设备名称" v-model="box.equName">
|
||||
</view>
|
||||
</view>
|
||||
<view class="tinput">
|
||||
|
||||
<view class="text1">
|
||||
<text class="hong1">*</text>
|
||||
设备型号
|
||||
</view>
|
||||
<view class="you">
|
||||
<input type="text" placeholder="请输入设备型号" v-model="box.equModel">
|
||||
</view>
|
||||
</view>
|
||||
<view class="tinput">
|
||||
|
||||
<view class="text1">
|
||||
<text class="hong1">*</text>
|
||||
设备编号
|
||||
</view>
|
||||
<view class="you">
|
||||
<input type="text" placeholder="请输入设备编号" v-model="box.equNumber">
|
||||
</view>
|
||||
</view>
|
||||
<view class="tinput" @click="typeShow = true">
|
||||
<view class="text1">
|
||||
设备类别
|
||||
</view>
|
||||
<view class="you">
|
||||
<input type="text" disabled placeholder="请选择设备类别" v-model="typeName">
|
||||
</view>
|
||||
</view>
|
||||
<view class="tinput">
|
||||
|
||||
<view class="text1">
|
||||
<text class="hong1">*</text>
|
||||
设备检定周期
|
||||
</view>
|
||||
<view class="you">
|
||||
<input type="text" placeholder="请输入设备检定周期" v-model="box.equZq">
|
||||
</view>
|
||||
</view>
|
||||
<view class="tinput">
|
||||
|
||||
<view class="text1">
|
||||
<text class="hong1">*</text>
|
||||
上次检定单位
|
||||
</view>
|
||||
<view class="you">
|
||||
<input type="text" placeholder="请输入上次检定单位" v-model="box.lastUnit">
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="tinput">
|
||||
<view class="text1">
|
||||
<text class="hong1">*</text>
|
||||
有效期
|
||||
</view>
|
||||
<!-- validTime -->
|
||||
<view class="you" @click="show = true ">
|
||||
<text>{{ time || '--' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tinput">
|
||||
<view class="text1">
|
||||
<text class="hong1">*</text>
|
||||
下次检定时间
|
||||
</view>
|
||||
<!-- nextCheckTime -->
|
||||
<view class="you" @click="show1 = true ">
|
||||
<text>{{ time1 || '--' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="tinput" v-if="type == 'edit'">
|
||||
<view class="text1">
|
||||
<text class="hong1">*</text>
|
||||
设备附件
|
||||
</view>
|
||||
<view class="lan_" @click="goFile">查看附件
|
||||
<image src="../../static/icons/internal/add.png" mode=""></image>
|
||||
</view>
|
||||
</view>
|
||||
<u-datetime-picker :show="show" v-model="box.validTime" @cancel="cancels" @confirm="confirms" mode="date"
|
||||
return-type='string'></u-datetime-picker>
|
||||
<u-datetime-picker :show="show1" v-model="box.nextCheckTime" @cancel="cancels1" @confirm="confirms1"
|
||||
mode="date" return-type='string'></u-datetime-picker>
|
||||
|
||||
<u-picker :show="typeShow" :columns="columns" @confirm="confirmsType" @cancel="typeShow = false"
|
||||
keyName="label"></u-picker>
|
||||
<view class="anniu" @click="getnewsadd()">
|
||||
<text>保存</text>
|
||||
</view>
|
||||
<view style="width: 100%; height: 60px;"></view>
|
||||
</view>
|
||||
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import request from '../../utils/request'
|
||||
import config from '@/config'
|
||||
import {
|
||||
getToken
|
||||
} from '@/utils/auth'
|
||||
import upload from '@/utils/upload.js'
|
||||
import {
|
||||
getDictByCode,
|
||||
getDictDataByType
|
||||
} from "../../utils/utils";
|
||||
import VNavigationBar from "@/components/VNavigationBar.vue";
|
||||
|
||||
var wvCurrent;
|
||||
export default {
|
||||
components: {
|
||||
VNavigationBar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
time: '请选择有效期',
|
||||
time1: '请选择下次检定时间',
|
||||
value1: '2023-10-10',
|
||||
baseUrl: this.$baseUrl,
|
||||
show: false,
|
||||
show1: false,
|
||||
fileId: null,
|
||||
id: '',
|
||||
type: 'add',
|
||||
box: {},
|
||||
typeShow: false,
|
||||
columns: [],
|
||||
typeName: null,
|
||||
//附件列表
|
||||
fileList3: [],
|
||||
pageName: '新增设备',
|
||||
baseImageUrl: config.baseImageUrl,
|
||||
}
|
||||
},
|
||||
onLoad(option) {
|
||||
this.type = option.type
|
||||
if (option.type == 'edit') {
|
||||
this.box.id = option.id
|
||||
this.pageName = '编辑设备'
|
||||
}
|
||||
this.getInsType()
|
||||
},
|
||||
|
||||
onShow() {
|
||||
if (this.type == 'edit') this.getDetail();
|
||||
},
|
||||
methods: {
|
||||
confirmsType(e) {
|
||||
console.log(e)
|
||||
this.box.type = e.value[0].value
|
||||
this.typeName = e.value[0].label
|
||||
this.typeShow = false
|
||||
},
|
||||
async getInsType() {
|
||||
if (!this.columns || this.columns.length === 0) {
|
||||
this.columns = [await getDictByCode("repair_equ_type")]
|
||||
}
|
||||
console.log(this.columns)
|
||||
},
|
||||
async getDetail() {
|
||||
let res = await request({
|
||||
url: '/admin-api/system/equInfo/' + this.box.id,
|
||||
method: 'get'
|
||||
})
|
||||
if (res.code == 200) {
|
||||
this.box = res.data
|
||||
if (this.box.fileList) {
|
||||
this.fileList3 = this.box.fileList
|
||||
// 在回显时给 URL 加上域名
|
||||
this.fileList3 = this.fileList3.map(file => {
|
||||
// 如果是相对路径,添加域名
|
||||
file.url = this.baseImageUrl + '/' + file.url;
|
||||
return file;
|
||||
});
|
||||
}
|
||||
// this.maneizhi = this.box.type
|
||||
this.time = this.box.validTime
|
||||
this.time1 = this.box.nextCheckTime
|
||||
}
|
||||
if (this.box.type) {
|
||||
const data = this.columns[0]
|
||||
const index = data.findIndex(item => item.value === this.box.type)
|
||||
if (index !== -1) {
|
||||
this.typeName = data[index].label
|
||||
}
|
||||
}
|
||||
},
|
||||
cancels() {
|
||||
this.show = false
|
||||
},
|
||||
cancels1() {
|
||||
this.show1 = false
|
||||
},
|
||||
confirms(e) {
|
||||
var timestamp = e.value;
|
||||
var date = new Date(timestamp);
|
||||
var year = date.getFullYear();
|
||||
var month = ("0" + (date.getMonth() + 1)).slice(-2);
|
||||
var day = ("0" + date.getDate()).slice(-2);
|
||||
var formattedDate = year + "-" + month + "-" + day;
|
||||
this.box.validTime = formattedDate
|
||||
this.time = formattedDate
|
||||
this.show = false
|
||||
|
||||
},
|
||||
confirms1(e) {
|
||||
var timestamp = e.value;
|
||||
var date = new Date(timestamp);
|
||||
var year = date.getFullYear();
|
||||
var month = ("0" + (date.getMonth() + 1)).slice(-2);
|
||||
var day = ("0" + date.getDate()).slice(-2);
|
||||
var formattedDate = year + "-" + month + "-" + day;
|
||||
this.box.nextCheckTime = formattedDate
|
||||
this.time1 = formattedDate
|
||||
this.show1 = false
|
||||
|
||||
},
|
||||
//发布按钮
|
||||
async getnewsadd() {
|
||||
this.box.fileList = this.fileList3.map(file => {
|
||||
// 去掉域名,返回相对路径
|
||||
if (file.url && file.url.startsWith(this.baseImageUrl)) {
|
||||
file.url = file.url.replace(this.baseImageUrl, '');
|
||||
}
|
||||
return file;
|
||||
});
|
||||
if (this.type == 'add') {
|
||||
this.box.servicePackageId = 'wexiu'
|
||||
let res = await request({
|
||||
url: '/admin-api/system/equInfo/add',
|
||||
method: 'post',
|
||||
data: this.box
|
||||
})
|
||||
if (res.code == 200) {
|
||||
uni.showToast({
|
||||
title: '发布成功'
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.navigateBack({
|
||||
delta: 1
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
if (this.type == 'edit') {
|
||||
let res = await request({
|
||||
url: '/admin-api/system/equInfo/edit',
|
||||
method: 'post',
|
||||
data: this.box
|
||||
})
|
||||
if (res.code == 200) {
|
||||
uni.showToast({
|
||||
title: '发布成功'
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.navigateBack({
|
||||
delta: 1
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
getback() {
|
||||
uni.navigateBack({
|
||||
delta: 1,
|
||||
})
|
||||
},
|
||||
|
||||
// 删除图片
|
||||
deletePic(event) {
|
||||
this[`fileList${event.name}`].splice(event.index, 1);
|
||||
},
|
||||
// 新增图片
|
||||
async afterRead(event) {
|
||||
// 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式
|
||||
let lists = [].concat(event.file);
|
||||
let fileListLen = this[`fileList${event.name}`].length;
|
||||
lists.map((item) => {
|
||||
this[`fileList${event.name}`].push({
|
||||
...item,
|
||||
status: "uploading",
|
||||
message: "上传中",
|
||||
});
|
||||
});
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
const result = await this.uploadFilePromise(lists[i].url);
|
||||
let item = this[`fileList${event.name}`][fileListLen];
|
||||
this[`fileList${event.name}`].splice(
|
||||
fileListLen,
|
||||
1,
|
||||
Object.assign(item, {
|
||||
status: "success",
|
||||
message: "",
|
||||
url: result,
|
||||
})
|
||||
);
|
||||
fileListLen++;
|
||||
}
|
||||
console.log('现在文件集合', this[`fileList${event.name}`])
|
||||
},
|
||||
uploadFilePromise(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
upload({
|
||||
url: '/common/upload',
|
||||
filePath: url,
|
||||
}).then((res) => {
|
||||
resolve(res.data.url);
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
goFile() {
|
||||
if (!this.box.id) {
|
||||
uni.showToast({
|
||||
title: '请先新建设备',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!this.box.folderId) {
|
||||
console.log('当前员工没有文件加')
|
||||
//给当前设备创建一个文件夹
|
||||
request({
|
||||
url: '/admin-api/system/equInfo/addDeviceFolder',
|
||||
method: 'post',
|
||||
params: {
|
||||
id: this.box.id,
|
||||
servicePackageId: 'jiuyuan',
|
||||
defaultKey: 'jy_equipment'
|
||||
},
|
||||
}).then(res => {
|
||||
this.box.folderId = res.data
|
||||
uni.navigateTo({
|
||||
url: '/pages-internal/dataManagement/deviceManage?type=staff&folderId=' + this
|
||||
.box
|
||||
.folderId
|
||||
})
|
||||
})
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: '/pages-internal/dataManagement/deviceManage?type=staff&folderId=' + this.box.folderId
|
||||
})
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.content {
|
||||
/* width: 100%;
|
||||
height: calc(100vh);
|
||||
background-color: #F6F6F6;
|
||||
box-sizing: border-box; */
|
||||
// padding-top: 45px;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background-color: #F6F6F6;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.dil {
|
||||
/* box-sizing: border-box;
|
||||
background-color: #F6F6F6;
|
||||
padding: 0px 12px; */
|
||||
box-sizing: border-box;
|
||||
background-color: #F6F6F6;
|
||||
padding: 0px 12px;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
|
||||
}
|
||||
|
||||
.lan_ {
|
||||
font-size: 28rpx;
|
||||
color: #327DFB;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
image {
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
margin-left: 15rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.top-icon {
|
||||
margin-bottom: 45px;
|
||||
}
|
||||
|
||||
.c-top {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 15px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: white;
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
.c-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
.top {
|
||||
box-sizing: border-box;
|
||||
padding: 0px 15px;
|
||||
width: 100%;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.top-box {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
padding: 20px 0px;
|
||||
}
|
||||
|
||||
.tb-left {
|
||||
height: 100%;
|
||||
width: 80%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.uicon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
background: orangered;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
margin-right: 6px;
|
||||
|
||||
}
|
||||
|
||||
.tb-right {
|
||||
width: 20px;
|
||||
height: 26px;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.text1 {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #363636;
|
||||
}
|
||||
|
||||
.hong1 {
|
||||
margin-top: 5px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #FF5453;
|
||||
}
|
||||
|
||||
.hong2 {
|
||||
margin-top: 5px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
|
||||
}
|
||||
|
||||
.tinput {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
background: white;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
padding: 16px;
|
||||
margin-top: 14px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.xinput {
|
||||
width: 100%;
|
||||
background: white;
|
||||
box-sizing: border-box;
|
||||
padding: 16px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.you {
|
||||
text-align: right;
|
||||
|
||||
}
|
||||
|
||||
.xz {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
|
||||
.kuang {
|
||||
width: 80px;
|
||||
height: 23px;
|
||||
background: #ECECEC;
|
||||
border-radius: 5px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #666666;
|
||||
font-size: 14px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.xlan {
|
||||
background: #CDE7FF !important;
|
||||
color: #1D62FF !important;
|
||||
border: 1px solid #2A96FE;
|
||||
}
|
||||
|
||||
.anniu {
|
||||
width: 100%;
|
||||
//background: linear-gradient(180deg, #3F61C0 0%, #0D2E8D 100%);
|
||||
color: #0174F6;
|
||||
border-radius: 50px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
//color: #542F0E;
|
||||
border: 1px solid #0174F6;
|
||||
margin-top: 20px;
|
||||
|
||||
}
|
||||
|
||||
|
||||
button::after {
|
||||
border: none;
|
||||
}
|
||||
</style>
|
310
pages-internal/deviceManagement/informationManage.vue
Normal file
@ -0,0 +1,310 @@
|
||||
<template>
|
||||
<view class="content">
|
||||
<VNavigationBar style="position: relative;z-index: 99;" homeHeaderPaddingTop="0" backgroundColor="#fff"
|
||||
title-color="#000" title="设备管理"></VNavigationBar>
|
||||
|
||||
<!-- 固定部分:搜索框 -->
|
||||
<view class="search_box">
|
||||
<u-search placeholder="请输入设备名称..." @clear="getlistindex()" @search="getlistindex()" :showAction="false"
|
||||
v-model="equName" searchIconColor="#427FFE"></u-search>
|
||||
</view>
|
||||
|
||||
<!-- 固定部分:新增按钮 -->
|
||||
<view class="add-btn" @click="goadd('add')">
|
||||
<text>+ 新增设备</text>
|
||||
</view>
|
||||
|
||||
<!-- 固定部分:Tab切换(横向滚动) -->
|
||||
<view class="tab-scroll-container">
|
||||
<scroll-view class="tab-scroll-view" scroll-x="true" shows-horizontal-scroll-indicator="false">
|
||||
<view class="tap-box" v-for="(item,index) in tabList" :key="index" @click="gettap(item.value)">
|
||||
<view :class="{'lan' : tapindex == item.value}">{{ item.label }}</view>
|
||||
<view class="gang" v-if="tapindex == item.value"></view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 滚动部分:设备列表 -->
|
||||
<view class="list-container">
|
||||
<!-- 有数据时显示列表 -->
|
||||
<view class="c-box" v-for="(item,index) in arrlist" :key="index" v-if="arrlist.length > 0">
|
||||
<view class="box-top">
|
||||
<view>{{ item.equName || '设备名称' }}</view>
|
||||
<view style="display: flex;align-items: center; justify-content: space-between; width: 25%;">
|
||||
<view style="color: #43A045;" @click="goadd('edit',item.id)">编辑</view>
|
||||
<view style="color: #FF7272;" @click="dialogToggle(item.id)">删除</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="box-hui">
|
||||
<view class="box-left">设备型号:</view>
|
||||
<view>{{ item.equModel || '' }}</view>
|
||||
</view>
|
||||
<view class="box-hui">
|
||||
<view class="box-left">设备编号:</view>
|
||||
<view>{{ item.equNumber || '' }}</view>
|
||||
</view>
|
||||
<view class="box-hui">
|
||||
<view class="box-left">检定/校准周期:</view>
|
||||
<view>{{ item.equZq || '' }}</view>
|
||||
</view>
|
||||
<view class="box-hui">
|
||||
<view class="box-left">有效期:</view>
|
||||
<view>{{ item.validTime || '' }}</view>
|
||||
</view>
|
||||
<view class="box-hui">
|
||||
<view class="box-left">检定单位:</view>
|
||||
<view>{{ item.lastUnit || '' }}</view>
|
||||
</view>
|
||||
<view class="box-hui">
|
||||
<view class="box-left">计划检定时间:</view>
|
||||
<view>{{ item.nextCheckTime || '' }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 无数据时显示提示 -->
|
||||
<view class="empty-tips" v-if="arrlist.length === 0">
|
||||
<image src="/static/internal/empty.png" class="empty-img"></image>
|
||||
<!-- <text>暂无设备</text> -->
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<uni-popup ref="alertDialog" type="dialog">
|
||||
<uni-popup-dialog cancelText="关闭" confirmText="同意" title="通知" content="您确认要删除吗" @confirm="dialogConfirm"
|
||||
@close="dialogClose"></uni-popup-dialog>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import config from '@/config'
|
||||
import request from '../../utils/request';
|
||||
import VNavigationBar from "@/components/VNavigationBar.vue";
|
||||
import {
|
||||
getDictByCode
|
||||
} from "../../utils/utils";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VNavigationBar
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
partnerId: '',
|
||||
arrlist: [],
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
totalPages: 0,
|
||||
deleteid: '',
|
||||
equName: null,
|
||||
tabList: [{
|
||||
label: "全部",
|
||||
value: "0"
|
||||
}],
|
||||
tapindex: 0,
|
||||
type: null
|
||||
}
|
||||
},
|
||||
onLoad(data) {
|
||||
this.partnerId = uni.getStorageSync('partnerId')
|
||||
if (data.value) {
|
||||
this.tapindex = parseInt(data.value)
|
||||
this.type = data.value === '0' ? null : data.value
|
||||
}
|
||||
this.getlistindex()
|
||||
this.getTab()
|
||||
},
|
||||
onShow() {
|
||||
// this.getlistindex()
|
||||
},
|
||||
onReachBottom() {
|
||||
if (this.pageNum >= this.totalPages) {
|
||||
uni.showToast({
|
||||
title: '没有下一页数据',
|
||||
icon: 'none'
|
||||
})
|
||||
} else {
|
||||
this.pageNum++
|
||||
this.getlistindex()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
gettap(value) {
|
||||
this.tapindex = value
|
||||
this.type = value === '0' ? null : value
|
||||
this.getlistindex()
|
||||
},
|
||||
async getTab() {
|
||||
const data = await getDictByCode("repair_equ_type");
|
||||
console.log('data123', data)
|
||||
this.tabList = [...this.tabList, ...data];
|
||||
console.log('this.tabList', this.tabList)
|
||||
},
|
||||
dialogToggle(id) {
|
||||
this.deleteid = id
|
||||
this.$refs.alertDialog.open()
|
||||
},
|
||||
async dialogConfirm() {
|
||||
let res = await request({
|
||||
url: '/admin-api/system/equInfo/' + this.deleteid,
|
||||
method: 'delete',
|
||||
})
|
||||
if (res.code == 200) {
|
||||
this.$refs.alertDialog.close()
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '删除成功'
|
||||
})
|
||||
this.getlistindex()
|
||||
}
|
||||
},
|
||||
dialogClose() {
|
||||
this.$refs.alertDialog.close()
|
||||
},
|
||||
goadd(type, id) {
|
||||
uni.navigateTo({
|
||||
url: '/pages-internal/deviceManagement/informationAdd?type=' + type + '&id=' + id
|
||||
})
|
||||
},
|
||||
async getlistindex() {
|
||||
let res = await request({
|
||||
url: '/admin-api/system/equInfo/list',
|
||||
method: 'get',
|
||||
data: {
|
||||
pageSize: this.pageSize,
|
||||
pageNum: this.pageNum,
|
||||
equName: this.equName,
|
||||
type: this.type,
|
||||
servicePackageId: 'weixiu'
|
||||
}
|
||||
})
|
||||
if (this.pageNum != 1) {
|
||||
this.arrlist = this.arrlist.concat(res.rows)
|
||||
} else {
|
||||
this.arrlist = res.rows
|
||||
}
|
||||
let total = res.total
|
||||
this.totalPages = Math.ceil(total / this.pageSize);
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.content {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background-color: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 固定搜索框 */
|
||||
.search_box {
|
||||
padding: 10px 15px;
|
||||
background: white;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
}
|
||||
|
||||
/* 固定新增按钮 */
|
||||
.add-btn {
|
||||
width: 100%;
|
||||
color: #0174F6;
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
font-weight: bold;
|
||||
border-radius: 8px;
|
||||
margin: 10px 15px;
|
||||
width: calc(100% - 30px);
|
||||
border: 1px solid #0174F6;
|
||||
position: sticky;
|
||||
top: 50px;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
/* Tab横向滚动容器 */
|
||||
.tab-scroll-container {
|
||||
background: white;
|
||||
position: sticky;
|
||||
top: 100px;
|
||||
z-index: 8;
|
||||
border-bottom: 1px solid #f5f5f5;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.tab-scroll-view {
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.tap-box {
|
||||
display: inline-block;
|
||||
min-width: 80px;
|
||||
text-align: center;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.gang {
|
||||
height: 4px;
|
||||
background: #327DFB;
|
||||
width: 80%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.lan {
|
||||
color: #0D2E8D;
|
||||
}
|
||||
|
||||
/* 滚动列表容器 */
|
||||
.list-container {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
/* 列表项样式 */
|
||||
.c-box {
|
||||
background: #F7F8FC;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.box-top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #eee;
|
||||
margin-bottom: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.box-hui {
|
||||
display: flex;
|
||||
margin-bottom: 5px;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.box-left {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/* 空列表提示 */
|
||||
.empty-tips {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px 0;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.empty-img {
|
||||
width: 240px;
|
||||
height: 200px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
26
pages/white/white.vue
Normal file
@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'White',
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
uni.navigateBack()
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
BIN
static/icons/internal/add.png
Normal file
After Width: | Height: | Size: 550 B |
BIN
static/icons/internal/device.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
static/icons/internal/s1.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
static/icons/tabbar/new-home-checked.png
Normal file
After Width: | Height: | Size: 768 B |
BIN
static/icons/tabbar/new-home.png
Normal file
After Width: | Height: | Size: 796 B |
BIN
static/images/business/text_left.png
Normal file
After Width: | Height: | Size: 259 B |
BIN
static/images/icon_tap.png
Normal file
After Width: | Height: | Size: 501 B |
BIN
static/images/j1.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
static/images/j2.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
static/images/j3.png
Normal file
After Width: | Height: | Size: 993 B |
BIN
static/images/j4.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
static/images/r1.png
Normal file
After Width: | Height: | Size: 851 B |
BIN
static/images/r2.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
static/images/t1.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/images/t2.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
static/images/t3.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
static/images/table_header.png
Normal file
After Width: | Height: | Size: 77 KiB |
BIN
static/images/ttel.png
Normal file
After Width: | Height: | Size: 930 B |
BIN
static/images/yh.png
Normal file
After Width: | Height: | Size: 14 KiB |
26
utils/fixScreen.js
Normal file
@ -0,0 +1,26 @@
|
||||
// common/fixScreen.js
|
||||
|
||||
/**
|
||||
* 修复 APP 端横竖屏切换后页面元素放大问题
|
||||
* 使用方式:在页面 onShow 中调用 fixScreen()
|
||||
*/
|
||||
export function fixScreen() {
|
||||
// #ifdef APP-PLUS
|
||||
try {
|
||||
console.log('执行缩放比');
|
||||
const pages = getCurrentPages();
|
||||
const page = pages[pages.length - 1];
|
||||
const currentWebview = page.$getAppWebview();
|
||||
|
||||
if (currentWebview) {
|
||||
// 强制重置缩放比例,避免放大
|
||||
currentWebview.setStyle({
|
||||
scalable: false, // 禁止缩放
|
||||
viewport: "device-width" // 保持设备宽度
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("fixScreen 执行失败:", e);
|
||||
}
|
||||
// #endif
|
||||
}
|