1014 lines
22 KiB
Vue
1014 lines
22 KiB
Vue
<template>
|
||
<view class="page">
|
||
<u-navbar title="换电工单" :border-bottom="false" :background="bgc" back-icon-color="#000" title-color='#000'
|
||
title-size='36' height='44'></u-navbar>
|
||
|
||
<!-- 顶部固定区域 -->
|
||
<view class="fixed-header">
|
||
<!-- 搜索栏 -->
|
||
<view class="search-box">
|
||
<view class="search-bar">
|
||
<view class="scan-btn" @click="btnsaoma">
|
||
<u-icon name="scan" size="40" color="#333"></u-icon>
|
||
</view>
|
||
<view class="divider"></view>
|
||
<input type="text" v-model="sn" placeholder="搜索车辆编号/换电工单" placeholder-class="placeholder-style" />
|
||
<view class="search-btn" @click="btnsousuo">
|
||
<u-icon name="search" size="40" color="#4C97E7"></u-icon>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 筛选栏 -->
|
||
<view class="filter-box">
|
||
<view class="tab-list">
|
||
<view class="tab-item" v-for="(item,index) in tablist" :key="index"
|
||
:class="{active: tabindex == index}" @click="btntab(item,index)">
|
||
{{item.name}}
|
||
<view class="active-indicator" v-if="tabindex == index"></view>
|
||
</view>
|
||
</view>
|
||
<view class="filter-option" @click="btndj">
|
||
<view class="custom-checkbox" :class="{checked: !chenchex}">
|
||
<u-icon name="checkmark" color="#fff" size="20" v-if="!chenchex"></u-icon>
|
||
</view>
|
||
<text>仅看我的</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 列表区域 -->
|
||
<scroll-view @scrolltolower="handqixing" scroll-y refresher-enabled @refresherrefresh="onRefresh"
|
||
:refresher-triggered="isRefreshing" class="list-container">
|
||
|
||
<!-- 占位元素,把内容顶下来 -->
|
||
<!-- <view style="height: 220rpx;"></view> -->
|
||
|
||
<view class="card" v-for="(item,index) in hdlist" :key="index" @click="btnitem(item)">
|
||
<!-- 卡片头部 -->
|
||
<view class="card-header">
|
||
<view class="order-info">
|
||
<text class="no">No.{{item.no}}</text>
|
||
</view>
|
||
<view class="status-badge" :class="'status-' + item.status">
|
||
<text v-if="item.status == 1">待接单</text>
|
||
<text v-else-if="item.status == 2">进行中</text>
|
||
<text v-else-if="item.status == 3">已完成</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 卡片内容 -->
|
||
<view class="card-body">
|
||
<view class="info-row time-row">
|
||
<u-icon name="clock" size="28" color="#999" style="margin-right: 8rpx;"></u-icon>
|
||
<text>{{item.createTime}}</text>
|
||
</view>
|
||
|
||
<view class="info-grid">
|
||
<view class="grid-item">
|
||
<text class="label">当前电量</text>
|
||
<text class="value highlight">{{item.createPower}}%</text>
|
||
</view>
|
||
<view class="grid-item">
|
||
<text class="label">车牌号</text>
|
||
<text class="value">{{item.deviceVehicleNum || '暂无'}}</text>
|
||
</view>
|
||
<view class="grid-item full-width">
|
||
<text class="label">设备编号</text>
|
||
<text class="value">{{item.deviceSn}}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 卡片底部操作 -->
|
||
<view class="card-footer" v-if="item.status != 3">
|
||
<view class="spacer"></view>
|
||
<view class="action-btn primary" v-if="item.status == 1" @click.stop="btnjd(item,index)">
|
||
立即接单
|
||
</view>
|
||
<view class="action-btn success" v-if="item.status == 2" @click.stop="btnwc(item,index)">
|
||
确认完成
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="loading-text">
|
||
{{ total > hdlist.length ? '加载中...' : '当前没有更多工单咯' }}
|
||
</view>
|
||
<view style="height: 150rpx;"></view>
|
||
</scroll-view>
|
||
|
||
<!-- 悬浮添加按钮 -->
|
||
<view class="fab-add" @click="btnaddflag">
|
||
<u-icon name="plus" color="#fff" size="48"></u-icon>
|
||
</view>
|
||
|
||
<!-- 完成输入备注弹窗 -->
|
||
<view class="modal-mask" v-if="beizhuflag" @click="btnqx"></view>
|
||
<view class="custom-modal" v-if="beizhuflag">
|
||
<view class="modal-title">工单备注</view>
|
||
<textarea class="modal-textarea" v-model="finishRemark" placeholder="请输入完成备注信息..." fixed="true"></textarea>
|
||
<view class="modal-footer">
|
||
<view class="btn cancel" @click="btnqx">取消</view>
|
||
<view class="btn confirm" @click="btnqdwc">完成</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 新增工单弹窗 -->
|
||
<view class="modal-mask" v-if="addflag" @click="btnyc"></view>
|
||
<view class="add-popup" v-if="addflag">
|
||
<view class="popup-header">
|
||
<text class="title">添加换电工单</text>
|
||
<view class="close-btn" @click="btnyc">
|
||
<u-icon name="close" size="32" color="#999"></u-icon>
|
||
</view>
|
||
</view>
|
||
|
||
<scroll-view scroll-y class="popup-body">
|
||
<!-- 选择设备 -->
|
||
<view class="form-section">
|
||
<view class="section-title">选择设备</view>
|
||
<view class="search-input-group">
|
||
<view class="scan-mini" @click="btnsaoma">
|
||
<u-icon name="scan" size="36" color="#333"></u-icon>
|
||
</view>
|
||
<view class="v-divider"></view>
|
||
<input type="text" v-model="bianhao" placeholder="输入车辆编号/车牌号" />
|
||
<view class="add-btn-mini" @click="btnadd">添加</view>
|
||
</view>
|
||
|
||
<view class="selected-tags">
|
||
<view class="tag-item" v-for="(item,index) in addlist" :key="index">
|
||
<text>{{item.sn}} {{item.vehicleNum ? `(${item.vehicleNum})` : ''}}</text>
|
||
<u-icon name="close-circle-fill" color="#ff4d4f" size="32" @click="btndel(item)" style="margin-left: 10rpx;"></u-icon>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 派发人员 -->
|
||
<view class="form-section">
|
||
<view class="section-title">派发人员</view>
|
||
<view class="select-box" @click="btnry">
|
||
<text :class="{placeholder: renyuan === '请选择'}">{{renyuan}}</text>
|
||
<u-icon :name="renyuanflag ? 'arrow-up' : 'arrow-down'" color="#999" size="28"></u-icon>
|
||
</view>
|
||
|
||
<view class="dropdown-list" v-if="renyuanflag">
|
||
<view class="dropdown-item" v-for="(item,index) in xzlist" :key="index" @click="btnrenyuan(item)">
|
||
<text class="name">{{item.userName}}</text>
|
||
<text class="remark">{{item.remark || '无备注'}}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 备注 -->
|
||
<view class="form-section">
|
||
<view class="section-title">备注信息</view>
|
||
<textarea class="form-textarea" v-model="txtcont" placeholder="请输入工单备注..." fixed="true"></textarea>
|
||
</view>
|
||
</scroll-view>
|
||
|
||
<view class="popup-footer">
|
||
<view class="submit-btn" @click="btnaddqd">确认创建</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
data() {
|
||
return {
|
||
tablist: [{
|
||
name: '待换电',
|
||
type: '1'
|
||
}, {
|
||
name: '换电中',
|
||
type: '2'
|
||
}, {
|
||
name: '已完成',
|
||
type: '3'
|
||
}, {
|
||
name: '全部',
|
||
type: '4'
|
||
}],
|
||
bgc: {
|
||
backgroundColor: "#fff",
|
||
},
|
||
areaId: '',
|
||
chenchex: true, // 注意:原逻辑 true 是 "未选中" (check value=true 点击变 false), false 是 "选中"
|
||
tabindex: 0,
|
||
pageNum: 1,
|
||
hdlist: [],
|
||
total: 0,
|
||
isRefreshing: false,
|
||
status: 1,
|
||
userId: '',
|
||
beizhuflag: false,
|
||
wcid: '',
|
||
wcindex: '',
|
||
finishRemark: '',
|
||
sn: '',
|
||
txtcont: '',
|
||
xzlist: [],
|
||
renyuan: '请选择',
|
||
renyuanid: '',
|
||
renyuanflag: false,
|
||
bianhao: '',
|
||
addlist: [],
|
||
addflag: false
|
||
}
|
||
},
|
||
onLoad(option) {
|
||
this.areaId = option.areaId
|
||
this.getlist()
|
||
this.getshebei()
|
||
},
|
||
methods: {
|
||
// 点击确定添加工单
|
||
btnaddqd() {
|
||
let arrid = []
|
||
this.addlist.forEach(item => {
|
||
arrid.push(item.id)
|
||
})
|
||
let data = {
|
||
deviceIds: arrid,
|
||
receiveUserId: this.renyuanid,
|
||
createRemark: this.txtcont
|
||
}
|
||
this.$u.post(`/bst/powerWork`, data).then(res => {
|
||
if (res.code == 200) {
|
||
this.addflag = false
|
||
this.pageNum = 1
|
||
this.addlist = []
|
||
this.getlist()
|
||
uni.showToast({
|
||
title: '添加成功',
|
||
icon: 'success',
|
||
duration: 3000
|
||
})
|
||
} else {
|
||
uni.showToast({
|
||
title: res.msg,
|
||
icon: 'none',
|
||
duration: 3000
|
||
})
|
||
}
|
||
})
|
||
},
|
||
// 点击显示添加工单
|
||
btnaddflag() {
|
||
this.addflag = true
|
||
},
|
||
// 点击隐藏添加工单
|
||
btnyc() {
|
||
this.addflag = false
|
||
this.addlist = []
|
||
},
|
||
// 点击删除设备
|
||
btndel(item) {
|
||
const deviceId = item.id
|
||
this.addlist = this.addlist.filter(item => item.id !== deviceId)
|
||
console.log(this.addlist);
|
||
},
|
||
// 点击添加设备
|
||
btnadd() {
|
||
if (!this.bianhao) return;
|
||
this.$u.get(`/bst/device?keyword=${this.bianhao}`).then(res => {
|
||
if (res.code == 200) {
|
||
if (res.data) {
|
||
this.bianhao = ''
|
||
const isExist = this.addlist.some(item => item.id == res.data.id)
|
||
if (isExist) {
|
||
uni.showToast({
|
||
title: '该设备已存在',
|
||
icon: 'none',
|
||
duration: 3000
|
||
})
|
||
} else {
|
||
this.addlist.push(res.data)
|
||
console.log(this.addlist);
|
||
}
|
||
} else {
|
||
uni.showToast({
|
||
title: '未查询到该设备',
|
||
icon: 'none',
|
||
duration: 2000
|
||
})
|
||
}
|
||
} else {
|
||
uni.showToast({
|
||
title: res.msg,
|
||
icon: 'none',
|
||
duration: 2000
|
||
})
|
||
}
|
||
})
|
||
},
|
||
// 点击显示人员列表
|
||
btnry() {
|
||
this.renyuanflag = !this.renyuanflag
|
||
},
|
||
// 点击选择派发人员
|
||
btnrenyuan(item) {
|
||
this.renyuan = item.userName
|
||
this.renyuanid = item.userId
|
||
this.renyuanflag = false
|
||
},
|
||
// 请求运营区所有人员
|
||
getshebei() {
|
||
this.$u.get(`/bst/areaJoin/list?areaId=${this.areaId}&pageNum=1&pageSize=999`).then(res => {
|
||
if (res.code == 200) {
|
||
this.xzlist = res.rows
|
||
}
|
||
})
|
||
},
|
||
|
||
btnqx() {
|
||
this.beizhuflag = false
|
||
},
|
||
// 点击跳转详情
|
||
btnitem(item) {
|
||
uni.navigateTo({
|
||
url: '/page_shanghu/yunwei/gongdanxq?id=' + item.id
|
||
})
|
||
},
|
||
|
||
// 点击进行搜索
|
||
btnsousuo() {
|
||
this.pageNum = 1
|
||
this.getlist()
|
||
},
|
||
// 点击扫码
|
||
btnsaoma() {
|
||
uni.scanCode({
|
||
onlyFromCamera: true,
|
||
scanType: ['qrCode'],
|
||
success: res => {
|
||
console.log(res)
|
||
function getQueryParam(url, paramName) {
|
||
let regex = new RegExp(`[?&]${paramName}=([^&]*)`)
|
||
let results = regex.exec(url)
|
||
return results ? decodeURIComponent(results[1].replace(/\+/g, ' ')) : null
|
||
}
|
||
let sceneValue = res.result
|
||
let decodedValue = decodeURIComponent(sceneValue)
|
||
this.sn = getQueryParam(decodedValue, 's') || getQueryParam(decodedValue, 'sn')
|
||
this.bianhao = getQueryParam(decodedValue, 's') || getQueryParam(decodedValue, 'sn')
|
||
this.pageNum = 1
|
||
this.getlist()
|
||
},
|
||
fail: err => {
|
||
console.error('扫描失败:', err)
|
||
uni.showToast({
|
||
title: '扫描失败',
|
||
icon: 'none',
|
||
duration: 2000
|
||
})
|
||
}
|
||
})
|
||
},
|
||
// 点击完成
|
||
btnwc(item, index) {
|
||
this.beizhuflag = true
|
||
this.wcid = item.id
|
||
this.wcindex = index
|
||
// this.getlist() // 没必要重新获取列表
|
||
},
|
||
//点击确定完成
|
||
btnqdwc() {
|
||
let data = {
|
||
id: this.wcid,
|
||
finishRemark: this.finishRemark
|
||
}
|
||
this.$u.put(`/bst/powerWork/complete`, data).then(res => {
|
||
if (res.code == 200) {
|
||
uni.showToast({
|
||
title: '操作完成',
|
||
icon: 'success',
|
||
duration: 2000
|
||
})
|
||
this.hdlist[this.wcindex].status = 3
|
||
this.beizhuflag = false
|
||
} else {
|
||
uni.showToast({
|
||
title: res.msg,
|
||
icon: 'none',
|
||
duration: 2000
|
||
})
|
||
}
|
||
})
|
||
},
|
||
// 点击接单
|
||
btnjd(item, index) {
|
||
let that = this
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '您是否要进行接单?',
|
||
showCancel: true,
|
||
success: function(res) {
|
||
if (res.confirm) {
|
||
let data = {
|
||
id: item.id
|
||
}
|
||
that.$u.put(`/bst/powerWork/receive`, data).then(res => {
|
||
if (res.code == 200) {
|
||
uni.showToast({
|
||
title: '接单成功',
|
||
icon: 'success',
|
||
duration: 2000
|
||
})
|
||
that.hdlist[index].status = 2
|
||
} else {
|
||
uni.showToast({
|
||
title: res.msg,
|
||
icon: 'none',
|
||
duration: 2000
|
||
})
|
||
}
|
||
})
|
||
} else if (res.cancel) {
|
||
|
||
}
|
||
}
|
||
})
|
||
},
|
||
// 点击是否只查看自己的
|
||
btndj() {
|
||
this.chenchex = !this.chenchex
|
||
if (this.chenchex == false) {
|
||
this.userId = uni.getStorageSync('user').userId
|
||
this.pageNum = 1
|
||
this.getlist()
|
||
} else {
|
||
this.userId = ''
|
||
this.pageNum = 1
|
||
this.getlist()
|
||
}
|
||
console.log(this.chenchex);
|
||
},
|
||
// 点击切换tab
|
||
btntab(item, index) {
|
||
this.tabindex = index
|
||
this.status = item.type
|
||
this.pageNum = 1
|
||
this.getlist()
|
||
},
|
||
// 获取换电工单列表
|
||
getlist() {
|
||
this.$u.get(
|
||
`/bst/powerWork/list?pageNum=${this.pageNum}&pageSize=20&areaId=${this.areaId}&status=${this.status == 4 ? '' : this.status}&receiveUserId=${this.userId}&keyword=${this.sn}`
|
||
).then((res) => {
|
||
if (res.code === 200) {
|
||
this.total = res.total
|
||
if (this.pageNum == 1) {
|
||
this.hdlist = res.rows
|
||
} else {
|
||
this.hdlist = this.hdlist.concat(res.rows)
|
||
}
|
||
}
|
||
})
|
||
},
|
||
handqixing() {
|
||
console.log(1);
|
||
if (this.hdlist.length < this.total) {
|
||
this.pageNum++ // 这里需要增加页码
|
||
this.getlist()
|
||
}
|
||
},
|
||
// 下拉刷新
|
||
onRefresh() {
|
||
this.isRefreshing = true
|
||
setTimeout(() => {
|
||
this.isRefreshing = false
|
||
this.pageNum = 1
|
||
this.getlist()
|
||
}, 1000)
|
||
},
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
page {
|
||
background: #F7F7F7;
|
||
}
|
||
|
||
.page {
|
||
width: 100%;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
/* 固定头部 */
|
||
.fixed-header {
|
||
// position: fixed;
|
||
// top: 0;
|
||
/* 注意:这里top设为0,实际可能需要避开navbar高度,或者navbar是占位的? */
|
||
/* u-navbar默认是fixed的,如果不占位,需要margin-top。根据原代码推测,这里需要用margin-top来避开navbar */
|
||
/* u-navbar :height="44" -> 88rpx. + statusbar height. */
|
||
/* 为了简单适配,建议给list-container加padding-top,header用z-index覆盖 */
|
||
/* 这里我们将header放在navbar下面 */
|
||
// margin-top: calc(44px + var(--status-bar-height));
|
||
// left: 0;
|
||
width: 100%;
|
||
z-index: 10;
|
||
background-color: #fff;
|
||
box-shadow: 0 2rpx 10rpx rgba(0,0,0,0.05);
|
||
}
|
||
|
||
/* 搜索栏 */
|
||
.search-box {
|
||
padding: 20rpx 30rpx;
|
||
background: #fff;
|
||
|
||
.search-bar {
|
||
display: flex;
|
||
align-items: center;
|
||
background: #F5F7FA;
|
||
border-radius: 40rpx;
|
||
padding: 12rpx 24rpx;
|
||
height: 80rpx;
|
||
box-sizing: border-box;
|
||
|
||
.scan-btn {
|
||
padding: 10rpx;
|
||
}
|
||
|
||
.divider {
|
||
width: 2rpx;
|
||
height: 32rpx;
|
||
background: #DCDFE6;
|
||
margin: 0 20rpx;
|
||
}
|
||
|
||
input {
|
||
flex: 1;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
}
|
||
|
||
.placeholder-style {
|
||
color: #999;
|
||
}
|
||
|
||
.search-btn {
|
||
padding: 10rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 筛选栏 */
|
||
.filter-box {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 0 30rpx;
|
||
height: 88rpx;
|
||
background: #fff;
|
||
border-top: 1rpx solid #f0f0f0;
|
||
|
||
.tab-list {
|
||
display: flex;
|
||
gap: 40rpx;
|
||
|
||
.tab-item {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
position: relative;
|
||
padding: 20rpx 0;
|
||
font-weight: 500;
|
||
|
||
&.active {
|
||
color: #4C97E7;
|
||
font-weight: 600;
|
||
font-size: 30rpx;
|
||
}
|
||
|
||
.active-indicator {
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 40rpx;
|
||
height: 6rpx;
|
||
background: #4C97E7;
|
||
border-radius: 4rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
.filter-option {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
|
||
.custom-checkbox {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
border: 2rpx solid #ccc;
|
||
border-radius: 6rpx;
|
||
margin-right: 12rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
&.checked {
|
||
background: #4C97E7;
|
||
border-color: #4C97E7;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 列表容器 */
|
||
.list-container {
|
||
height: 75vh;
|
||
box-sizing: border-box;
|
||
padding: 0 24rpx;
|
||
padding-top: 24rpx;
|
||
}
|
||
|
||
/* 卡片样式 */
|
||
.card {
|
||
background: #FFFFFF;
|
||
border-radius: 20rpx;
|
||
padding: 30rpx;
|
||
margin-bottom: 24rpx;
|
||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.03);
|
||
|
||
.card-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding-bottom: 24rpx;
|
||
border-bottom: 1rpx solid #f5f5f5;
|
||
margin-bottom: 24rpx;
|
||
|
||
.no {
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
}
|
||
|
||
.status-badge {
|
||
padding: 6rpx 20rpx;
|
||
border-radius: 30rpx;
|
||
font-size: 24rpx;
|
||
|
||
&.status-1 {
|
||
background: #FFF0F0;
|
||
color: #FF4D4F;
|
||
}
|
||
&.status-2 {
|
||
background: #EBF4FF;
|
||
color: #4C97E7;
|
||
}
|
||
&.status-3 {
|
||
background: #F0F9EB;
|
||
color: #67C23A;
|
||
}
|
||
}
|
||
}
|
||
|
||
.card-body {
|
||
.info-row {
|
||
display: flex;
|
||
align-items: center;
|
||
font-size: 26rpx;
|
||
color: #999;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.info-grid {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
background: #F8F9FB;
|
||
border-radius: 12rpx;
|
||
padding: 20rpx;
|
||
|
||
.grid-item {
|
||
width: 50%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
margin-bottom: 16rpx;
|
||
|
||
&.full-width {
|
||
width: 100%;
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.label {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
margin-bottom: 8rpx;
|
||
}
|
||
|
||
.value {
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
font-weight: 500;
|
||
word-break: break-all;
|
||
|
||
&.highlight {
|
||
color: #4C97E7;
|
||
font-weight: bold;
|
||
font-size: 32rpx;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.card-footer {
|
||
margin-top: 24rpx;
|
||
display: flex;
|
||
|
||
.spacer {
|
||
flex: 1;
|
||
}
|
||
|
||
.action-btn {
|
||
min-width: 160rpx;
|
||
height: 64rpx;
|
||
border-radius: 32rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 28rpx;
|
||
font-weight: 500;
|
||
|
||
&.primary {
|
||
background: #4C97E7;
|
||
color: #fff;
|
||
box-shadow: 0 4rpx 12rpx rgba(76, 151, 231, 0.3);
|
||
}
|
||
|
||
&.success {
|
||
background: #67C23A;
|
||
color: #fff;
|
||
box-shadow: 0 4rpx 12rpx rgba(103, 194, 58, 0.3);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.loading-text {
|
||
text-align: center;
|
||
color: #999;
|
||
font-size: 24rpx;
|
||
padding: 30rpx 0;
|
||
}
|
||
|
||
/* 悬浮按钮 */
|
||
.fab-add {
|
||
position: fixed;
|
||
right: 40rpx;
|
||
bottom: 180rpx;
|
||
width: 110rpx;
|
||
height: 110rpx;
|
||
background: #4C97E7;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
box-shadow: 0 8rpx 20rpx rgba(76, 151, 231, 0.4);
|
||
z-index: 100;
|
||
transition: all 0.2s;
|
||
|
||
&:active {
|
||
transform: scale(0.95);
|
||
}
|
||
}
|
||
|
||
/* 弹窗通用 */
|
||
.modal-mask {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: rgba(0,0,0,0.6);
|
||
z-index: 990;
|
||
}
|
||
|
||
/* 备注弹窗 */
|
||
.custom-modal {
|
||
position: fixed;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: 600rpx;
|
||
background: #fff;
|
||
border-radius: 24rpx;
|
||
padding: 40rpx;
|
||
z-index: 999;
|
||
|
||
.modal-title {
|
||
font-size: 34rpx;
|
||
font-weight: 600;
|
||
text-align: center;
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.modal-textarea {
|
||
width: 100%;
|
||
height: 240rpx;
|
||
background: #F5F7FA;
|
||
border-radius: 12rpx;
|
||
padding: 20rpx;
|
||
box-sizing: border-box;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.modal-footer {
|
||
display: flex;
|
||
gap: 30rpx;
|
||
margin-top: 40rpx;
|
||
|
||
.btn {
|
||
flex: 1;
|
||
height: 80rpx;
|
||
border-radius: 40rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 30rpx;
|
||
|
||
&.cancel {
|
||
background: #F5F7FA;
|
||
color: #666;
|
||
}
|
||
|
||
&.confirm {
|
||
background: #4C97E7;
|
||
color: #fff;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 新增工单弹窗 */
|
||
.add-popup {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 80vh;
|
||
background: #fff;
|
||
border-radius: 30rpx 30rpx 0 0;
|
||
z-index: 999;
|
||
display: flex;
|
||
flex-direction: column;
|
||
|
||
.popup-header {
|
||
padding: 30rpx 40rpx;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
border-bottom: 1rpx solid #f5f5f5;
|
||
|
||
.title {
|
||
font-size: 34rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
}
|
||
}
|
||
|
||
.popup-body {
|
||
flex: 1;
|
||
padding: 30rpx 40rpx;
|
||
box-sizing: border-box;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.form-section {
|
||
margin-bottom: 40rpx;
|
||
|
||
.section-title {
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.search-input-group {
|
||
display: flex;
|
||
align-items: center;
|
||
background: #F5F7FA;
|
||
border-radius: 12rpx;
|
||
padding: 10rpx 20rpx;
|
||
border: 1rpx solid #E4E7ED;
|
||
|
||
.v-divider {
|
||
width: 2rpx;
|
||
height: 30rpx;
|
||
background: #DCDFE6;
|
||
margin: 0 20rpx;
|
||
}
|
||
|
||
input {
|
||
flex: 1;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.add-btn-mini {
|
||
background: #4C97E7;
|
||
color: #fff;
|
||
font-size: 24rpx;
|
||
padding: 10rpx 24rpx;
|
||
border-radius: 8rpx;
|
||
}
|
||
}
|
||
|
||
.selected-tags {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 20rpx;
|
||
margin-top: 20rpx;
|
||
|
||
.tag-item {
|
||
background: #EBF4FF;
|
||
color: #4C97E7;
|
||
padding: 12rpx 24rpx;
|
||
border-radius: 30rpx;
|
||
font-size: 26rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
}
|
||
|
||
.select-box {
|
||
background: #F5F7FA;
|
||
padding: 24rpx;
|
||
border-radius: 12rpx;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
|
||
.placeholder {
|
||
color: #999;
|
||
}
|
||
}
|
||
|
||
.dropdown-list {
|
||
margin-top: 10rpx;
|
||
background: #fff;
|
||
border: 1rpx solid #E4E7ED;
|
||
border-radius: 12rpx;
|
||
max-height: 300rpx;
|
||
overflow-y: auto;
|
||
box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.05);
|
||
|
||
.dropdown-item {
|
||
padding: 20rpx;
|
||
border-bottom: 1rpx solid #f5f5f5;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
|
||
&:active {
|
||
background: #F5F7FA;
|
||
}
|
||
|
||
.name { font-size: 28rpx; color: #333; }
|
||
.remark { font-size: 24rpx; color: #999; }
|
||
}
|
||
}
|
||
|
||
.form-textarea {
|
||
width: 100%;
|
||
height: 200rpx;
|
||
background: #F5F7FA;
|
||
border-radius: 12rpx;
|
||
padding: 20rpx;
|
||
box-sizing: border-box;
|
||
font-size: 28rpx;
|
||
}
|
||
}
|
||
|
||
.popup-footer {
|
||
padding: 20rpx 40rpx;
|
||
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||
border-top: 1rpx solid #f5f5f5;
|
||
|
||
.submit-btn {
|
||
width: 100%;
|
||
height: 88rpx;
|
||
background: #4C97E7;
|
||
border-radius: 44rpx;
|
||
color: #fff;
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
&:active {
|
||
opacity: 0.9;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style> |