473 lines
13 KiB
Vue
473 lines
13 KiB
Vue
|
|
<template>
|
|||
|
|
<view class="page">
|
|||
|
|
<u-navbar :title="navTitle" :border-bottom="false" :background="bgc" back-icon-color="#111827" title-color="#111827" title-size="34" height="44"></u-navbar>
|
|||
|
|
|
|||
|
|
<view class="summary-card" v-if="form.abilityName || form.areaName">
|
|||
|
|
<text class="summary-name">{{ form.abilityName || '--' }}</text>
|
|||
|
|
<text class="summary-area">{{ form.areaName || '--' }}</text>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="page-loading" v-if="loading">加载中...</view>
|
|||
|
|
|
|||
|
|
<scroll-view v-else scroll-y class="form-scroll">
|
|||
|
|
<!-- 基础设置 -->
|
|||
|
|
<view class="section">
|
|||
|
|
<view class="section-head">
|
|||
|
|
<view class="section-bar"></view>
|
|||
|
|
<text class="section-title">基础设置</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="switch-row">
|
|||
|
|
<view class="switch-info">
|
|||
|
|
<text class="switch-title">启用能力</text>
|
|||
|
|
<text class="switch-desc">关闭后该能力不可用</text>
|
|||
|
|
</view>
|
|||
|
|
<switch :checked="!!form.enabled" color="#4297F3" data-field="enabled" @change="onFormSwitch" />
|
|||
|
|
</view>
|
|||
|
|
<!-- <view class="switch-row">
|
|||
|
|
<view class="switch-info">
|
|||
|
|
<text class="switch-title">免费使用</text>
|
|||
|
|
<text class="switch-desc">开启后免费,关闭则按套餐收费</text>
|
|||
|
|
</view>
|
|||
|
|
<switch :checked="!!form.free" color="#4297F3" data-field="free" @change="onFormSwitch" />
|
|||
|
|
</view> -->
|
|||
|
|
<view class="switch-row">
|
|||
|
|
<view class="switch-info">
|
|||
|
|
<text class="switch-title">用量预警</text>
|
|||
|
|
<text class="switch-desc">剩余次数不足时提醒</text>
|
|||
|
|
</view>
|
|||
|
|
<switch :checked="!!form.enableWarn" color="#4297F3" data-field="enableWarn" @change="onFormSwitch" />
|
|||
|
|
</view>
|
|||
|
|
<view class="form-field" v-if="form.enableWarn">
|
|||
|
|
<text class="field-label">预警阈值</text>
|
|||
|
|
<text class="field-tip">剩余次数低于该值时将触发预警</text>
|
|||
|
|
<view class="input-box">
|
|||
|
|
<input class="field-input" type="number" v-model="form.warnCount" placeholder="请输入预警阈值" />
|
|||
|
|
<text class="field-unit">次</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 团购设置 -->
|
|||
|
|
<view class="section" v-if="isCouponVerify">
|
|||
|
|
<view class="section-head">
|
|||
|
|
<view class="section-bar"></view>
|
|||
|
|
<text class="section-title">团购设置</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="form-field">
|
|||
|
|
<text class="field-label">抖音门店</text>
|
|||
|
|
<text class="field-tip">抖音生活服务门店 POI ID,登录抖音来客后在门店管理查看</text>
|
|||
|
|
<view class="input-box input-box--block">
|
|||
|
|
<input class="field-input" v-model="form.settings.douyinPoiId" placeholder="请输入抖音门店 POI ID" />
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
<view class="form-field">
|
|||
|
|
<text class="field-label">抖音根账户</text>
|
|||
|
|
<text class="field-tip">抖音根账户 ID,登录抖音来客后在右上角账户管理查看</text>
|
|||
|
|
<view class="input-box input-box--block">
|
|||
|
|
<input class="field-input" v-model="form.settings.douyinAccountId" placeholder="请输入抖音根账户 ID" />
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 保障设置 -->
|
|||
|
|
<view class="section" v-if="isInsurance">
|
|||
|
|
<view class="section-head">
|
|||
|
|
<view class="section-bar"></view>
|
|||
|
|
<text class="section-title">保障设置</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="switch-row">
|
|||
|
|
<view class="switch-info">
|
|||
|
|
<text class="switch-title">强制投保</text>
|
|||
|
|
<text class="switch-desc">开启后用户下单强制购买保险</text>
|
|||
|
|
</view>
|
|||
|
|
<switch :checked="!!form.settings.insuranceRequired" color="#4297F3" data-field="insuranceRequired" @change="onSettingsSwitch" />
|
|||
|
|
</view>
|
|||
|
|
<view class="form-field">
|
|||
|
|
<text class="field-label">定价</text>
|
|||
|
|
<text class="field-tip">自定义保险价格</text>
|
|||
|
|
<view class="input-box">
|
|||
|
|
<input class="field-input" type="digit" v-model="form.settings.insurancePrice" placeholder="请输入定价" />
|
|||
|
|
<text class="field-unit">元/次</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<!-- 实名设置 -->
|
|||
|
|
<view class="section" v-if="isRealName">
|
|||
|
|
<view class="section-head">
|
|||
|
|
<view class="section-bar"></view>
|
|||
|
|
<text class="section-title">实名设置</text>
|
|||
|
|
</view>
|
|||
|
|
<view class="form-field">
|
|||
|
|
<text class="field-label">最低年龄</text>
|
|||
|
|
<text class="field-tip">若无需校验可填 0</text>
|
|||
|
|
<view class="input-box">
|
|||
|
|
<input class="field-input" type="number" v-model="form.settings.minAge" placeholder="请输入最低用车年龄" />
|
|||
|
|
<text class="field-unit">岁</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
<view class="form-field">
|
|||
|
|
<text class="field-label">最高年龄</text>
|
|||
|
|
<text class="field-tip">若无需校验可填 1000</text>
|
|||
|
|
<view class="input-box">
|
|||
|
|
<input class="field-input" type="number" v-model="form.settings.maxAge" placeholder="请输入最高用车年龄" />
|
|||
|
|
<text class="field-unit">岁</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
|
|||
|
|
<view class="scroll-bottom-space"></view>
|
|||
|
|
</scroll-view>
|
|||
|
|
|
|||
|
|
<view class="footer-bar" v-if="!loading">
|
|||
|
|
<view hover-class="app-tap-hover" class="footer-btn footer-btn--ghost" @tap="goBack">取消</view>
|
|||
|
|
<view hover-class="app-tap-hover" class="footer-btn footer-btn--primary" @tap="submitForm">
|
|||
|
|
<text>保存</text>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</view>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
import { AbilityCode } from '@/common/enums/ability.js'
|
|||
|
|
|
|||
|
|
const DEFAULT_SETTINGS = {
|
|||
|
|
douyinPoiId: '',
|
|||
|
|
douyinAccountId: '',
|
|||
|
|
insuranceRequired: false,
|
|||
|
|
insurancePrice: '',
|
|||
|
|
minAge: '',
|
|||
|
|
maxAge: ''
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export default {
|
|||
|
|
data() {
|
|||
|
|
return {
|
|||
|
|
bgc: { backgroundColor: '#fff' },
|
|||
|
|
AbilityCode,
|
|||
|
|
id: '',
|
|||
|
|
loading: false,
|
|||
|
|
submitting: false,
|
|||
|
|
form: {
|
|||
|
|
id: null,
|
|||
|
|
enabled: true,
|
|||
|
|
free: false,
|
|||
|
|
enableWarn: true,
|
|||
|
|
warnCount: 100,
|
|||
|
|
abilityCode: '',
|
|||
|
|
abilityName: '',
|
|||
|
|
areaName: '',
|
|||
|
|
settings: { ...DEFAULT_SETTINGS }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
computed: {
|
|||
|
|
navTitle() {
|
|||
|
|
return '能力设置'
|
|||
|
|
},
|
|||
|
|
isCouponVerify() {
|
|||
|
|
return this.form.abilityCode === AbilityCode.COUPON_VERIFY
|
|||
|
|
},
|
|||
|
|
isInsurance() {
|
|||
|
|
return this.form.abilityCode === AbilityCode.INSURANCE
|
|||
|
|
},
|
|||
|
|
isRealName() {
|
|||
|
|
return this.form.abilityCode === AbilityCode.REAL_NAME
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
onLoad(e) {
|
|||
|
|
this.id = e.id || e.areaAbilityId || ''
|
|||
|
|
if (e.abilityCode) {
|
|||
|
|
this.form.abilityCode = decodeURIComponent(e.abilityCode)
|
|||
|
|
}
|
|||
|
|
if (e.abilityName) {
|
|||
|
|
this.form.abilityName = decodeURIComponent(e.abilityName)
|
|||
|
|
}
|
|||
|
|
if (e.areaName) {
|
|||
|
|
this.form.areaName = decodeURIComponent(e.areaName)
|
|||
|
|
}
|
|||
|
|
this.fetchDetail()
|
|||
|
|
},
|
|||
|
|
methods: {
|
|||
|
|
goBack() {
|
|||
|
|
uni.navigateBack()
|
|||
|
|
},
|
|||
|
|
normalizeForm(data) {
|
|||
|
|
const row = data || {}
|
|||
|
|
const settings = {
|
|||
|
|
...DEFAULT_SETTINGS,
|
|||
|
|
...(row.settings || {})
|
|||
|
|
}
|
|||
|
|
if (settings.insuranceRequired === 1 || settings.insuranceRequired === '1') {
|
|||
|
|
settings.insuranceRequired = true
|
|||
|
|
}
|
|||
|
|
if (settings.insuranceRequired === 0 || settings.insuranceRequired === '0') {
|
|||
|
|
settings.insuranceRequired = false
|
|||
|
|
}
|
|||
|
|
return {
|
|||
|
|
...row,
|
|||
|
|
id: row.id,
|
|||
|
|
enabled: row.enabled === true || row.enabled === 1 || row.enabled === '1',
|
|||
|
|
free: row.free === true || row.free === 1 || row.free === '1',
|
|||
|
|
enableWarn: row.enableWarn === true || row.enableWarn === 1 || row.enableWarn === '1',
|
|||
|
|
warnCount: row.warnCount != null && row.warnCount !== '' ? row.warnCount : 100,
|
|||
|
|
abilityCode: row.abilityCode || this.form.abilityCode || '',
|
|||
|
|
abilityName: row.abilityName || this.form.abilityName || '',
|
|||
|
|
areaName: row.areaName || this.form.areaName || '',
|
|||
|
|
settings
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
fetchDetail() {
|
|||
|
|
if (!this.id) {
|
|||
|
|
uni.showToast({ title: '缺少能力ID', icon: 'none' })
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
this.loading = true
|
|||
|
|
this.$u
|
|||
|
|
.get(`/bst/areaAbility/${this.id}`)
|
|||
|
|
.then((res) => {
|
|||
|
|
if (res.code == 200 && res.data) {
|
|||
|
|
this.form = this.normalizeForm(res.data)
|
|||
|
|
} else {
|
|||
|
|
uni.showToast({ title: res.msg || '加载失败', icon: 'none' })
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
.catch(() => {
|
|||
|
|
uni.showToast({ title: '加载失败', icon: 'none' })
|
|||
|
|
})
|
|||
|
|
.finally(() => {
|
|||
|
|
this.loading = false
|
|||
|
|
})
|
|||
|
|
},
|
|||
|
|
onFormSwitch(e) {
|
|||
|
|
const field = e.currentTarget.dataset.field
|
|||
|
|
if (!field) return
|
|||
|
|
this.$set(this.form, field, !!(e && e.detail && e.detail.value))
|
|||
|
|
},
|
|||
|
|
onSettingsSwitch(e) {
|
|||
|
|
const field = e.currentTarget.dataset.field
|
|||
|
|
if (!field) return
|
|||
|
|
this.$set(this.form.settings, field, !!(e && e.detail && e.detail.value))
|
|||
|
|
},
|
|||
|
|
validateForm() {
|
|||
|
|
if (this.form.enableWarn) {
|
|||
|
|
const n = Number(this.form.warnCount)
|
|||
|
|
if (!Number.isFinite(n) || this.form.warnCount === '' || this.form.warnCount == null) {
|
|||
|
|
uni.showToast({ title: '请输入用量预警阈值', icon: 'none' })
|
|||
|
|
return false
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return true
|
|||
|
|
},
|
|||
|
|
buildSubmitData() {
|
|||
|
|
const data = {
|
|||
|
|
...this.form,
|
|||
|
|
settings: { ...this.form.settings }
|
|||
|
|
}
|
|||
|
|
if (data.warnCount != null && data.warnCount !== '') {
|
|||
|
|
data.warnCount = Number(data.warnCount)
|
|||
|
|
}
|
|||
|
|
return data
|
|||
|
|
},
|
|||
|
|
submitForm() {
|
|||
|
|
if (this.submitting) return
|
|||
|
|
if (!this.validateForm()) return
|
|||
|
|
this.submitting = true
|
|||
|
|
uni.showLoading({ title: '保存中...', mask: true })
|
|||
|
|
this.$u
|
|||
|
|
.put('/bst/areaAbility', this.buildSubmitData())
|
|||
|
|
.then((res) => {
|
|||
|
|
if (res.code == 200) {
|
|||
|
|
uni.showToast({ title: '保存成功', icon: 'success' })
|
|||
|
|
const pages = getCurrentPages()
|
|||
|
|
const prev = pages[pages.length - 2]
|
|||
|
|
if (prev && prev.$vm) {
|
|||
|
|
prev.$vm._needRefresh = true
|
|||
|
|
}
|
|||
|
|
setTimeout(() => uni.navigateBack(), 500)
|
|||
|
|
} else {
|
|||
|
|
uni.showToast({ title: res.msg || '保存失败', icon: 'none' })
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
.catch(() => {
|
|||
|
|
uni.showToast({ title: '保存失败', icon: 'none' })
|
|||
|
|
})
|
|||
|
|
.finally(() => {
|
|||
|
|
this.submitting = false
|
|||
|
|
uni.hideLoading()
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style lang="scss">
|
|||
|
|
page {
|
|||
|
|
background: #f6f8fa;
|
|||
|
|
height: 100%;
|
|||
|
|
}
|
|||
|
|
.page {
|
|||
|
|
height: 100vh;
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
overflow: hidden;
|
|||
|
|
}
|
|||
|
|
.summary-card {
|
|||
|
|
flex-shrink: 0;
|
|||
|
|
margin: 16rpx 24rpx 0;
|
|||
|
|
padding: 20rpx 24rpx;
|
|||
|
|
background: #fff;
|
|||
|
|
border-radius: 12rpx;
|
|||
|
|
border: 1rpx solid #eef2f7;
|
|||
|
|
}
|
|||
|
|
.summary-name {
|
|||
|
|
display: block;
|
|||
|
|
font-size: 30rpx;
|
|||
|
|
font-weight: 600;
|
|||
|
|
color: #111827;
|
|||
|
|
}
|
|||
|
|
.summary-area {
|
|||
|
|
display: block;
|
|||
|
|
margin-top: 6rpx;
|
|||
|
|
font-size: 24rpx;
|
|||
|
|
color: #9ca3af;
|
|||
|
|
}
|
|||
|
|
.page-loading {
|
|||
|
|
flex: 1;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
color: #9ca3af;
|
|||
|
|
}
|
|||
|
|
.form-scroll {
|
|||
|
|
flex: 1;
|
|||
|
|
height: 0;
|
|||
|
|
padding: 16rpx 24rpx 0;
|
|||
|
|
box-sizing: border-box;
|
|||
|
|
}
|
|||
|
|
.section {
|
|||
|
|
background: #fff;
|
|||
|
|
border-radius: 12rpx;
|
|||
|
|
padding: 20rpx 24rpx;
|
|||
|
|
margin-bottom: 16rpx;
|
|||
|
|
border: 1rpx solid #eef2f7;
|
|||
|
|
}
|
|||
|
|
.section-head {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
margin-bottom: 16rpx;
|
|||
|
|
padding-bottom: 12rpx;
|
|||
|
|
border-bottom: 1rpx solid #f3f4f6;
|
|||
|
|
}
|
|||
|
|
.section-bar {
|
|||
|
|
width: 6rpx;
|
|||
|
|
height: 28rpx;
|
|||
|
|
background: #4297F3;
|
|||
|
|
border-radius: 4rpx;
|
|||
|
|
margin-right: 12rpx;
|
|||
|
|
}
|
|||
|
|
.section-title {
|
|||
|
|
font-size: 30rpx;
|
|||
|
|
font-weight: 600;
|
|||
|
|
color: #111827;
|
|||
|
|
}
|
|||
|
|
.switch-row {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
padding: 16rpx 0;
|
|||
|
|
border-bottom: 1rpx solid #f9fafb;
|
|||
|
|
&:last-child {
|
|||
|
|
border-bottom: none;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
.switch-info {
|
|||
|
|
flex: 1;
|
|||
|
|
min-width: 0;
|
|||
|
|
padding-right: 16rpx;
|
|||
|
|
}
|
|||
|
|
.switch-title {
|
|||
|
|
display: block;
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
color: #111827;
|
|||
|
|
font-weight: 500;
|
|||
|
|
}
|
|||
|
|
.switch-desc {
|
|||
|
|
display: block;
|
|||
|
|
margin-top: 4rpx;
|
|||
|
|
font-size: 22rpx;
|
|||
|
|
color: #9ca3af;
|
|||
|
|
line-height: 1.4;
|
|||
|
|
}
|
|||
|
|
.form-field {
|
|||
|
|
padding: 12rpx 0 4rpx;
|
|||
|
|
}
|
|||
|
|
.field-label {
|
|||
|
|
display: block;
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
font-weight: 500;
|
|||
|
|
color: #374151;
|
|||
|
|
}
|
|||
|
|
.field-tip {
|
|||
|
|
display: block;
|
|||
|
|
margin-top: 6rpx;
|
|||
|
|
font-size: 22rpx;
|
|||
|
|
color: #9ca3af;
|
|||
|
|
line-height: 1.45;
|
|||
|
|
}
|
|||
|
|
.input-box {
|
|||
|
|
margin-top: 12rpx;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
background: #f8fafc;
|
|||
|
|
border: 1rpx solid #e5e7eb;
|
|||
|
|
border-radius: 10rpx;
|
|||
|
|
padding: 0 20rpx;
|
|||
|
|
min-height: 72rpx;
|
|||
|
|
}
|
|||
|
|
.input-box--block {
|
|||
|
|
padding: 12rpx 20rpx;
|
|||
|
|
}
|
|||
|
|
.field-input {
|
|||
|
|
flex: 1;
|
|||
|
|
font-size: 28rpx;
|
|||
|
|
color: #111827;
|
|||
|
|
min-height: 48rpx;
|
|||
|
|
}
|
|||
|
|
.field-unit {
|
|||
|
|
flex-shrink: 0;
|
|||
|
|
margin-left: 12rpx;
|
|||
|
|
font-size: 26rpx;
|
|||
|
|
color: #6b7280;
|
|||
|
|
}
|
|||
|
|
.scroll-bottom-space {
|
|||
|
|
height: 140rpx;
|
|||
|
|
}
|
|||
|
|
.footer-bar {
|
|||
|
|
flex-shrink: 0;
|
|||
|
|
display: flex;
|
|||
|
|
gap: 20rpx;
|
|||
|
|
padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom));
|
|||
|
|
background: #fff;
|
|||
|
|
box-shadow: 0 -4rpx 16rpx rgba(0, 0, 0, 0.06);
|
|||
|
|
}
|
|||
|
|
.footer-btn {
|
|||
|
|
flex: 1;
|
|||
|
|
height: 84rpx;
|
|||
|
|
line-height: 84rpx;
|
|||
|
|
text-align: center;
|
|||
|
|
border-radius: 42rpx;
|
|||
|
|
font-size: 30rpx;
|
|||
|
|
font-weight: 600;
|
|||
|
|
}
|
|||
|
|
.footer-btn--ghost {
|
|||
|
|
background: #f3f4f6;
|
|||
|
|
color: #374151;
|
|||
|
|
}
|
|||
|
|
.footer-btn--primary {
|
|||
|
|
background: linear-gradient(135deg, #4297F3 0%, #2b76e5 100%);
|
|||
|
|
color: #fff;
|
|||
|
|
}
|
|||
|
|
</style>
|