This commit is contained in:
2026-02-10 09:56:08 +08:00
commit d7802b25f2
147 changed files with 17439 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
<template>
<view class="ant-layout-header header">
<uni-row>
<uni-col :span="6" style="text-align: left;">
<view class="ant-btn back" @click="back">返回</view>
</uni-col>
<uni-col :span="12">
<view class="title">
设置/{{ title }}
</view>
</uni-col>
<uni-col :span="6">
<slot name="rightBtn"></slot>
</uni-col>
</uni-row>
</view>
</template>
<script>
export default {
name: 'HeadTitle',
props: {
title: {
type: String,
default: '标题'
},
},
methods: {
back() {
uni.navigateBack({
delta: 1
})
}
}
}
</script>
<style scoped>
.header{
padding: 0 20px;
}
/* .header .ant-btn{
background: #2F3242;
border-color: #2F3242;
height: 46px;
width: 128px;
border-radius: 50px;
color: #fff;
font-size: 16px;
line-height: 38px;
} */
.header .title{
font-size: 24px;
color: #747A8D;
}
</style>
+118
View File
@@ -0,0 +1,118 @@
<template>
<a-modal v-model:visible="visible"
@ok="handleOk"
class="my-modal"
:footer="null"
:centered="true" :destroyOnClose="true">
<template #title>
<div class="title">
<span class="title-text">密码验证</span>
</div>
</template>
<div class="content">
<a-row class="code" type="flex" justify="center" align="center">
<a-col>
<span v-for="item in value" :key="item">
<b v-if="item != ' '">*</b>
</span>
</a-col>
</a-row>
<input-num
class="input-num"
:type="2"
ref="inputNum"
@enter="enter"
@input="input"
@backspace="backspace">
</input-num>
</div>
</a-modal>
</template>
<script>
import { trim } from 'lodash';
import InputNum from './InputNum.vue';
export default {
components: {
InputNum
},
data() {
return {
visible: false,
value: [" ", " ", " ", " "]
}
},
methods: {
show() {
this.visible = true
this.value = [" ", " ", " ", " "]
},
close() {
this.visible = false
},
handleOk() {
this.visible = false
},
backspace() {
let cur = this.value.findLastIndex(el => el !== " ")
if (cur >= 0) {
this.value[cur] = " "
}
},
input(val) {
let cur = this.value.findIndex(el => el === " ")
if (cur >= 0) {
this.value[cur] = val
}
},
enter() {
let value = this.value.toString()
value = value.replace(/,/g, "")
if (trim(value).length == 4) {
this.$emit("submit", value)
}
}
}
}
</script>
<style scoped>
.my-modal .title{
text-align: center;
font-size: 30px;
color: #fff;
}
.input-num :deep(.number){
background-color: #fff;
color: #5A5A5A;
font-weight: 700;
border-radius: 10px;
}
.code{
width: 100%;
margin-bottom: 20px;
}
.code .ant-col{
display: flex;
justify-content: space-around;
flex: 0 0 290px;
}
.code span{
text-align: center;
width: 56px;
height: 52px;
background-color: #fff;
border-radius: 10px;
color: #5A5A5A;
font-size: 20px;
font-weight: 700;
line-height: 52px;
}
</style>
+105
View File
@@ -0,0 +1,105 @@
<template>
<view>
<view style="max-width: 300px; margin: 0 auto;" >
<a-space style="flex-wrap: wrap; justify-content: center;display: flex;">
<view @click="input(i)" class="number" v-for="(i, k) in numbers" :key="k">{{i}}</view>
<view @click="input('.')" class="number" v-if="type == 1">·</view>
<view @click="enter" class="number" v-if="type == 2" style="font-weight: normal;">确认</view>
<view @click="input('0')" class="number">0</view>
<view @click="backspace" class="number" style="font-weight: normal;">删除</view>
</a-space>
<a-space style="flex-wrap: nowrap; justify-content: center; display: flex;">
</a-space>
</view>
</view>
</template>
<script>
export default {
props: {
type: { // 1: 数字,2: 金额
type: Number,
default: 1
}
},
data() {
return {
visible: false,
numbers: [1,2,3,4,5,6,7,8,9],
value: '',
isError: false
}
},
methods: {
init() {
this.value = ""
this.isError = false
},
input(val) {
this.value += val
this.$emit('input', val)
},
enter() {
this.$emit('enter', parseInt(this.value))
},
backspace() {
this.$emit('backspace')
// this.value = this.value.slice(0, -1)
},
open() {
this.init()
this.visible = true
},
close() {
this.visible = false
}
}
}
</script>
<style scoped>
.title{
text-align: center;
margin-bottom: 10px;
}
.input, .number{
width: 80px;
background: #2F3242;
color: #ADACAC;
display: inline-block;
border-radius: 60px;
font-size: 24px;
box-shadow: 0px 4px 10px 0px rgba(0, 0, 0, 0.1);
text-align: center;
font-weight: 600;
}
.input.error{
color: red;
border-color: red;
}
.number{
line-height: 76px;
font-size: 26px;
}
.number{
margin-bottom: 10px;
}
.input.val{
width: 100%;
font-size: 40px;
letter-spacing: 4px;
position: relative;
}
.input-addon{
position: absolute;
right: 16px;
color: #999;
}
</style>
+116
View File
@@ -0,0 +1,116 @@
<template>
<a-drawer
class="drawer"
placement="bottom"
:maskClosable="true"
height="480"
:visible="visible"
:destroyOnClose="true"
getContainer="#app"
:bodyStyle="{ background: '#f6f6f6', paddingTop: 0}"
:headerStyle="{ background: '#f6f6f6' }"
@close="close"
>
<a-row type="flex" justify="center">
<a-col style="max-width: 500px">
<div style="width: 100%;height: 80px; padding: 0 10px;">
<span class="input val">
{{ value }}
<span class="input-addon" @click="backspace" v-show="value.length > 0">
<arrow-left-outlined />
</span>
</span>
</div>
<a-space style="flex-wrap: wrap; justify-content: center;" :size="10">
<span @click="input(i)" class="number" v-for="(i, k) in numbers" :key="k">{{i}}</span>
</a-space>
<a-space style="margin-top:10px; width: 100%; justify-content: center;" :size="10">
<span @click="input('.')" class="number">·</span>
<span @click="input('0')" class="number">0</span>
<span @click="enter" class="number">确认</span>
</a-space>
</a-col>
</a-row>
</a-drawer>
</template>
<script>
export default {
data() {
return {
visible: false,
numbers: [1,2,3,4,5,6,7,8,9],
value: '',
isError: false
}
},
methods: {
init() {
this.value = ""
this.isError = false
},
input(val) {
this.value += val
this.$emit('input', val)
},
enter() {
this.$emit('submit', parseInt(this.value))
this.close()
},
backspace() {
this.value = this.value.slice(0, -1)
},
open() {
this.init()
this.visible = true
},
close() {
this.visible = false
}
}
}
</script>
<style scoped>
.title{
text-align: center;
margin-bottom: 10px;
}
.input, .number{
width: 152px;
height: 74px;
background: #fff;
color: #333;
display: inline-block;
line-height: 74px;
border-radius: 10px;
font-size: 24px;
border: 1px solid #eee;
box-shadow: 0px 4px 10px 0px rgba(0, 0, 0, 0.1);
text-align: center;
font-weight: 600;
}
.input.error{
color: red;
border-color: red;
}
.number{
height: 74px;
line-height: 74px;
font-size: 30px;
}
.input.val{
width: 100%;
font-size: 40px;
letter-spacing: 4px;
position: relative;
}
.input-addon{
position: absolute;
right: 16px;
color: #999;
}
</style>
+126
View File
@@ -0,0 +1,126 @@
<template>
<uni-popup ref="popup" type="center">
<view class="my-modal">
<view class="close" @click="close">
<uni-icons type="closeempty" size="40" color="#fff"></uni-icons>
</view>
<div class="title">
<span class="title-text">密码验证</span>
</div>
<div class="content">
<a-row class="code" type="flex" justify="center" align="center">
<a-col>
<span v-for="item in value" :key="item">
<b v-if="item != ' '">*</b>
</span>
</a-col>
</a-row>
<input-num
class="input-num"
:type="2"
ref="inputNum"
@enter="enter"
@input="input"
@backspace="backspace">
</input-num>
</div>
</view>
</uni-popup>
</template>
<script>
import { trim } from 'lodash';
import InputNum from './InputNum.vue';
export default {
name: "InputNumPop",
components: {
InputNum
},
data() {
return {
value: [" ", " ", " ", " "]
}
},
methods: {
show() {
this.$refs.popup.open()
this.value = [" ", " ", " ", " "]
},
close() {
this.$refs.popup.close()
},
backspace() {
for (let i = this.value.length - 1; i >= 0; i--) {
if (this.value[i] != " ") {
this.value[i] = " "
break
}
}
},
input(val) {
let cur = this.value.findIndex(el => el === " ")
if (cur >= 0) {
this.value[cur] = val
}
},
enter() {
let value = this.value.toString()
value = value.replace(/,/g, "")
if (trim(value).length == 4) {
this.$emit("submit", value)
}
}
}
}
</script>
<style scoped>
.my-modal{
background: #777D90;
padding: 30px;
width: 500px;
border-radius: 30px;
position: relative;
}
.my-modal .title{
text-align: center;
font-size: 30px;
color: #fff;
}
.input-num :deep(.number){
background-color: #fff;
color: #5A5A5A;
font-weight: 700;
border-radius: 10px;
}
.code{
width: 100%;
margin-bottom: 20px;
}
.code .ant-col{
display: flex;
justify-content: space-around;
flex: 0 0 290px;
}
.code span{
text-align: center;
width: 56px;
height: 52px;
background-color: #fff;
border-radius: 10px;
color: #5A5A5A;
font-size: 20px;
font-weight: 700;
line-height: 52px;
}
.close{
position: absolute;
top: 20px;
right: 20px;
line-height: 1;
}
</style>
+64
View File
@@ -0,0 +1,64 @@
<template>
<uni-popup ref="popup" type="center"
background-color="#777D90"
mask-background-color="rgba(0,0,0,0)"
@change="change">
<view class="pop-inner">
<view class="pop-title" v-if="title">{{ title }}</view>
<view class="pop-content" v-if="content">{{ content }}</view>
</view>
</uni-popup>
</template>
<script>
export default {
name: "Notice",
props: {
},
data() {
return {
title: '',
content: ''
}
},
methods: {
open(args) {
this.$nextTick(() => {
this.title = args.title
this.content = args.content
this.$refs.popup.open()
setTimeout(() => {
this.$refs.popup.close()
}, 3000)
})
},
close() {
this.$refs.popup.close()
},
change(e) {
}
}
}
</script>
<style scoped>
.pop-inner{
align-items: center;
display: flex;
justify-content: center;
width: 100%;
height: 100%;
flex-direction: column;
}
:deep(.uni-popup__wrapper.center){
text-align: center;
background-color: #777D90;
color: #fff;
height: 226px;
width: 504px;
font-size: 28px;
border-radius: 30px;
}
</style>
+109
View File
@@ -0,0 +1,109 @@
<template>
<view class="ant-layout-footer">
<view class="btn-group">
<view class="ant-btn-block" :class="isActive(item.path)" @click="btnClick(item)" v-for="(item, index) in menu" :key="index">
<template v-if="item.key == 1">
<uni-icons type="tune-filled" size="30"
:color="isActive(item.path) == 'primary' ? '#fff' : '#777d90'"></uni-icons>
</template>
<template v-if="item.key == 2">
<uni-icons type="list" size="30"
:color="isActive(item.path) == 'primary' ? '#fff' : '#777d90'"></uni-icons>
</template>
<template v-if="item.key == 3">
<uni-icons type="gear" size="30"
:color="isActive(item.path) == 'primary' ? '#fff' : '#777d90'"></uni-icons>
</template>
{{ item.label }}
</view>
</view>
</view>
</template>
<script>
export default {
name: 'page-footer',
data() {
return {
menu: [
{key: 1, label: '存储', path: 'pages/index'},
{key: 2, label: '日志', path: 'pages/log'},
{key: 3, label: '设置', path: 'pages/setting'},
]
}
},
computed: {
isActive() {
return (path) => {
const pages = getCurrentPages();
const cur = pages[pages.length - 1].route
return cur == path ? 'primary' : 'default'
}
}
},
mounted() {
},
methods: {
btnClick(item) {
if (item.path) {
uni.navigateTo({
url: '/' + item.path,
animationType: 'fade-in'
})
}
}
}
}
</script>
<style scoped>
.ant-layout-footer{
height: 70px;
padding: 0;
}
.btn-group{
width: 100%;
}
.ant-btn-block{
height: 70px;
line-height: 70px;
/* border-radius: 0;
border-bottom: 0; */
box-shadow: none;
font-size: 30px;
font-weight: 400;
background: #2f3242;
border-color: #2f3242;
color: #777d90;
flex:1;
}
.ant-btn-block.primary{
color: #fff;
}
.ant-btn-block{
border-right: 1px solid #fff;
}
.ant-btn-block:last-child{
border-right: 0;
}
.ant-btn-group > .ant-btn:last-child:not(:first-child),
.ant-btn-group > span:last-child:not(:first-child) > .ant-btn {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.ant-btn-group > .ant-btn:first-child:not(:last-child),
.ant-btn-group > span:first-child:not(:last-child) > .ant-btn {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
/* border-right-color: #2F3242; */
}
.ant-btn-group > .ant-btn-group .ant-btn-primary:first-child:not(:last-child){
border-right-color: #fff;
}
</style>
+133
View File
@@ -0,0 +1,133 @@
<template>
<a-layout-header>
<view class="status_bar">
<!-- 这里是状态栏 -->
</view>
<a-row justify="space-between" type="flex">
<a-col :span="12" @click="openDrawer">
<div class="title">
智能内镜储存柜
</div>
</a-col>
<a-col :span="12" align="center">
<div class="time">{{ currentTime }}</div>
</a-col>
</a-row>
</a-layout-header>
</template>
<script>
export default {
name: 'page-header',
data() {
return {
currentTime: this.setTime(),
signal: '4',
wifi: '3',
isWifi: false,
clickTimes: 0,
visible: false
}
},
created() {
},
mounted() {
this.interval = setInterval(() => this.setTime(), 1000)
},
beforeDestroy() {
clearInterval(this.interval)
},
methods: {
// back() {
// this.$emit('backEvent')
// },
setTime() {
this.currentTime = this.getCurrentTime()
},
getCurrentTime() {
const now = new Date();
// 获取时分秒
let hours = now.getHours();
let minutes = now.getMinutes();
let seconds = now.getSeconds();
// 格式化为两位数
hours = hours.toString().padStart(2, '0');
minutes = minutes.toString().padStart(2, '0');
seconds = seconds.toString().padStart(2, '0');
let year = now.getFullYear()+'-'+(now.getMonth()+1) +'-'+now.getDate()+' '
return `${year} ${hours}:${minutes}:${seconds}`;
},
openDrawer() {
this.clickTimes++
if (this.clickTimes == 5) {
this.visible = true
}
setTimeout(() => {
this.clickTimes = 0
}, 3000)
},
onClose() {
this.visible = false
},
quitApp() {
// ipc.invoke('controller.example.exitApp');
},
quitFull() {
// ipc.invoke('controller.example.exitFullWindow');
},
enterFull() {
// ipc.invoke('controller.example.setFullWindow');
}
}
}
</script>
<style scoped>
.status_bar{
height: 0;
}
.ant-layout-header{
height: 50px;
line-height: 48px;
padding: 0;
background: black;
}
.icon-signal{
display: inline-block;
margin: 4px 10px;
width: 40px;
height: 40px;
/* background-image: url('@/assets/icon/signal0.png'); */
background-position: center center;
background-size: 100% 100%;
}
.top-icon{
font-size:30px;
font-weight: 800;
color: #fff;
/* margin-top: 3px; */
}
.time{
color: #777D90;
line-height: 50px;
font-size: 18px;
letter-spacing: 2px;
}
.title{
color: #777D90;
line-height: 50px;
font-size: 18px;
text-align: left;
padding-left: 20px;
}
</style>
+10
View File
@@ -0,0 +1,10 @@
const modules = import.meta.globEager('./*.vue')
const map = {}
Object.keys(modules).forEach(file => {
const modulesName = file.replace('./', '').replace('.vue', '')
map[modulesName] = modules[file].default
})
const globalComponents = {
...map,
}
export default globalComponents
+195
View File
@@ -0,0 +1,195 @@
<template>
<view class="switch-container" :style="[{ background: bj_color}]">
<view class="switch_view">
<view
class="switch-item"
:class="{'checked_switch':isSwitch}"
:style="isSwitch?`color:${checked_color}`:''"
@click.prevent.stop="changeSwitch(true)"
:animation="animationData2"
>
{{switchList[0]}}
</view>
<view
class="switch-item"
:class="{'checked_switch':!isSwitch}"
:style="!isSwitch?`color:${checked_color}`:''"
@click.prevent.stop="changeSwitch(false)"
:animation="animationData3"
>
{{switchList[1]}}
</view>
</view>
<view class="disabled" v-if="disabled"></view>
<view
class="position_view" :animation="animationData1"
:style="[{ background: checked_bj_color}]"
></view>
</view>
</template>
<script>
export default {
props: {
switchList: {
type: Array,
default: ()=>{
return ['开','关'];
}
},
defaultSwitch:{ // 默认值
type:Boolean,
default:true
},
isShowModal:{//改变开关时,是否弹框提醒
type:Boolean,
default:false
},
disabled:{
type:Boolean,
default:false
},
bj_color:{
type:String,
default:'#fff'
},
checked_bj_color:{
type:String,
default:'#1989fa'
},
checked_color:{
type:String,
default:'#fff'
},
id:{
type:null,
default:null
}
},
watch:{
// 监听默认值
defaultSwitch(){
if(this.isSwitch != this.defaultSwitch){
this.isSwitch = this.defaultSwitch;
this.changeAnimation();
}
}
},
data () {
return {
isSwitch:true,
initAnimation:{},
animationData1: {},
animationData2: {},
animationData3: {}
};
},
created () {
this.initAnimation = uni.createAnimation({
duration: 500,
timingFunction: 'ease'
});
this.isSwitch = this.defaultSwitch;
this.changeAnimation();
},
methods: {
changeSwitch(isSwitch) {
if(isSwitch == this.isSwitch || this.disabled){
return;
}
if(this.isShowModal){
let index = isSwitch?0:1;
let text = this.switchList[index];
uni.showModal({
title: '提示',
content: `您确定要将其调整为${text}吗?`,
success: (res) => {
if(res.confirm){
this.isSwitch = isSwitch;
this.changeAnimation();
this.callParentEvent(isSwitch);
}
}
});
}else{
this.isSwitch = isSwitch;
this.changeAnimation();
this.callParentEvent(isSwitch);
}
},
// 动画效果
changeAnimation(){
if(this.isSwitch){
this.animationData1 = this.initAnimation.left(0).width('50%').step().export();
this.animationData2 = this.initAnimation.width('50%').step().export();
this.animationData3 = this.initAnimation.width('50%').step().export();
}else{
this.animationData1 = this.initAnimation.left('50%').width('50%').step().export();
this.animationData2 = this.initAnimation.width('50%').step().export();
this.animationData3 = this.initAnimation.width('50%').step().export();
}
},
// change回调
callParentEvent(){
this.$emit('change',this.isSwitch,this.id);
}
}
};
</script>
<style lang="scss" scoped>
.switch-container {
display: flex;
flex-direction: row;
width: 100%;
height: 40px;
border-radius: 0;
border: 1upx solid #ccc;
position: relative;
.switch_view{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
display: flex;
border-radius: 0;
.switch-item {
color: #666;
font-size: 18px;
height: 100%;
width: 40%;
border-radius: 0;
display: flex;
justify-content: center;
align-items: center;
opacity: .3;
}
.switch-item.checked_switch{
opacity: 1;
font-weight: 600;
}
}
.position_view{
position: absolute;
top: 0;
left: 0;
width: 60%;
height: 100%;
border-radius: 0;
background: $uni-color-primary;
}
.disabled{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 99;
background: #fff;
opacity: 0.6;
border-radius: 0;
}
}
</style>