Files
supplier-dispatch-h5/src/views/index/supplierTimePhoneEdit.vue
T

394 lines
8.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="wrap">
<van-nav-bar
:title="isEdit ? '编辑时段电话' : '新增时段电话'"
left-arrow
@click-left="h5GoBack"
fixed
placeholder
class="nav-bar"
/>
<div class="content">
<div class="field">
<label class="field-label">时段开始 结束格式 00:00 ~ 23:59</label>
<div class="period-row">
<input
type="text"
readonly
:value="form.startTime"
placeholder="开始时间"
@click="openTimePicker('startTime')"
/>
<span class="sep"></span>
<input
type="text"
readonly
:value="form.endTime"
placeholder="结束时间"
@click="openTimePicker('endTime')"
/>
</div>
<div v-if="periodErr" class="err-msg">{{ periodErr }}</div>
</div>
<div class="phone-block" v-for="n in 3" :key="n">
<div class="phone-block__head">
<span>电话 {{ n }}{{ n === 1 ? '(必填)' : '(选填)' }}</span>
</div>
<input
type="text"
v-model="form['phone' + n]"
:placeholder="'电话号码'"
/>
<div class="sub-grid">
<input
type="text"
v-model="form['phone' + n + 'Desc']"
placeholder="备注/负责人"
/>
<input
type="text"
v-model="form['phone' + n + 'WechatId']"
placeholder="微信号"
/>
</div>
<div v-if="phoneErr[n - 1]" class="err-msg">{{ phoneErr[n - 1] }}</div>
</div>
</div>
<div class="footer">
<button class="btn btn-save" @click="save">保存</button>
</div>
<van-popup v-model="showTimePicker" round position="bottom">
<van-datetime-picker
v-if="showTimePicker"
v-model="pickerValue"
type="time"
:formatter="timeFormatter"
@confirm="onTimeConfirm"
@cancel="showTimePicker = false"
/>
</van-popup>
</div>
</template>
<script>
import { myMixins } from '@/utils/myMixins'
import { isValidPhone, validateTimeRange } from '@/utils/validate'
import { Toast } from 'vant'
const DRAFT_KEY_PREFIX = 'supplierTimePhoneDraft_'
function getSupplierIdFromToken() {
const token = localStorage.getItem('token')
if (!token) return null
try {
const payload = JSON.parse(atob(token.split('.')[1]))
return payload.supplierId || null
} catch (e) {
return null
}
}
function getDraftKey(supplierId) {
return `${DRAFT_KEY_PREFIX}${supplierId}`
}
function emptyRecord() {
return {
startTime: '',
endTime: '',
phone1: '',
phone1Desc: '',
phone1WechatId: '',
phone2: '',
phone2Desc: '',
phone2WechatId: '',
phone3: '',
phone3Desc: '',
phone3WechatId: ''
}
}
export default {
name: 'supplierTimePhoneEdit',
mixins: [myMixins],
data() {
return {
supplierId: null,
index: -1,
form: emptyRecord(),
periodErr: '',
phoneErr: ['', '', ''],
showTimePicker: false,
pickerField: 'startTime',
pickerValue: ''
}
},
computed: {
isEdit() {
return this.index >= 0
}
},
mounted() {
this.supplierId = this.$route.query.supplierId || getSupplierIdFromToken()
this.index = Number(this.$route.query.index)
if (Number.isNaN(this.index)) {
this.index = -1
}
if (this.isEdit) {
this.loadRecord()
}
},
methods: {
validate() {
this.periodErr = ''
this.phoneErr = ['', '', '']
let valid = true
const timeRes = validateTimeRange(this.form.startTime, this.form.endTime)
if (!timeRes.valid) {
this.periodErr = timeRes.message
valid = false
}
if (!this.form.phone1) {
this.phoneErr[0] = '电话 1 为必填项'
valid = false
} else if (!isValidPhone(this.form.phone1)) {
this.phoneErr[0] = '电话 1 格式不正确'
valid = false
} else if (!this.form.phone1Desc) {
this.phoneErr[0] = '电话 1 备注为必填项'
valid = false
}
if (this.form.phone2) {
if (!isValidPhone(this.form.phone2)) {
this.phoneErr[1] = '电话 2 格式不正确'
valid = false
} else if (!this.form.phone2Desc) {
this.phoneErr[1] = '电话 2 备注为必填项'
valid = false
}
}
if (this.form.phone3) {
if (!isValidPhone(this.form.phone3)) {
this.phoneErr[2] = '电话 3 格式不正确'
valid = false
} else if (!this.form.phone3Desc) {
this.phoneErr[2] = '电话 3 备注为必填项'
valid = false
}
}
return valid
},
loadRecord() {
const key = getDraftKey(this.supplierId)
const raw = localStorage.getItem(key)
if (!raw) {
Toast('未找到时段数据')
this.h5GoBack()
return
}
try {
const draft = JSON.parse(raw)
const list = draft.phoneList || []
if (this.index >= 0 && this.index < list.length) {
this.form = { ...list[this.index] }
} else {
Toast('时段数据不存在')
this.h5GoBack()
}
} catch (e) {
console.error(e)
Toast('数据读取失败')
this.h5GoBack()
}
},
save() {
if (!this.validate()) return
try {
const key = getDraftKey(this.supplierId)
const draft = JSON.parse(localStorage.getItem(key) || '{}')
const list = draft.phoneList || []
const record = {
startTime: this.form.startTime,
endTime: this.form.endTime,
phone1: this.form.phone1,
phone1Desc: this.form.phone1Desc,
phone1WechatId: this.form.phone1WechatId,
phone2: this.form.phone2,
phone2Desc: this.form.phone2Desc,
phone2WechatId: this.form.phone2WechatId,
phone3: this.form.phone3,
phone3Desc: this.form.phone3Desc,
phone3WechatId: this.form.phone3WechatId
}
if (this.isEdit) {
list[this.index] = record
} else {
list.push(record)
}
draft.phoneList = list
localStorage.setItem(key, JSON.stringify(draft))
Toast('已保存')
this.h5GoBack()
} catch (e) {
Toast('保存失败')
console.error(e)
}
},
openTimePicker(field) {
this.pickerField = field
this.pickerValue = this.form[field] || '00:00'
this.showTimePicker = true
},
onTimeConfirm(value) {
this.form[this.pickerField] = value
this.showTimePicker = false
},
timeFormatter(type, value) {
return value.toString().padStart(2, '0')
}
}
}
</script>
<style scoped lang="scss">
@import "@/styles/mixin.scss";
@import "@/styles/common.scss";
.wrap {
@include wh(100%, 100%);
box-sizing: border-box;
background: #f4f5f7;
display: flex;
flex-direction: column;
}
::v-deep .nav-bar {
.van-nav-bar {
background: #2b6cff;
}
.van-nav-bar__title,
.van-nav-bar__arrow {
color: #fff;
}
}
.content {
flex: 1;
overflow-y: auto;
padding: 14px;
}
.field {
margin-bottom: 16px;
}
.field-label {
display: block;
font-size: 13px;
color: #333;
font-weight: 600;
margin-bottom: 7px;
}
.period-row {
display: flex;
align-items: center;
gap: 10px;
input {
flex: 1;
}
.sep {
color: #999;
}
}
input[type='text'] {
width: 100%;
height: 42px;
border: 1px solid #dfe1e6;
border-radius: 10px;
padding: 0 12px;
font-size: 14px;
color: #1a1a1a;
background: #fafbfc;
outline: none;
box-sizing: border-box;
&:focus {
border-color: #2b6cff;
background: #fff;
}
&[readonly] {
cursor: pointer;
}
}
.phone-block {
border: 1px solid #eef0f3;
border-radius: 12px;
padding: 12px;
margin-bottom: 12px;
background: #fcfcfd;
&__head {
display: flex;
justify-content: space-between;
font-size: 13px;
color: #2b6cff;
font-weight: 600;
margin-bottom: 8px;
}
.sub-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-top: 8px;
}
}
.err-msg {
color: #ff4d4f;
font-size: 12px;
margin-top: 6px;
}
.footer {
padding: 10px 12px;
background: #fff;
border-top: 1px solid #eee;
flex-shrink: 0;
display: flex;
flex-direction: row;
gap: 10px;
.btn {
flex: 1;
height: 46px;
border-radius: 12px;
border: none;
font-size: 15px;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
}
.btn-save {
background: #2b6cff;
color: #fff;
}
.btn-cancel {
background: #f2f3f5;
color: #666;
}
.btn-del {
background: #fff;
color: #ff4d4f;
border: 1.5px solid #ffccc7;
}
}
</style>