39 个文件按 .prettierrc.json (printWidth 100 / no semi / singleQuote) 统一格式, 纯空白与换行调整, 无逻辑变更。为接入代码门禁做准备, 让 npm run check (format:check + lint:strict + typecheck) 干净通过。
191 lines
5.4 KiB
Vue
191 lines
5.4 KiB
Vue
<script setup lang="ts">
|
|
import { readError } from '@/shared/utils/error'
|
|
import { ElMessage } from 'element-plus'
|
|
import { ref, watch } from 'vue'
|
|
|
|
import { updateSystemConfig, type SystemConfig } from '@/features/admin/api/systemConfigs'
|
|
import { safeParseJSON } from '@/shared/utils/json'
|
|
|
|
interface PostRentalNotice {
|
|
title: string
|
|
content: string
|
|
}
|
|
|
|
const defaultPostRentalNotice: PostRentalNotice = {
|
|
title: '租后须知(重要!)',
|
|
content: `一、上号前须知
|
|
|
|
1. 租期说明
|
|
租期内无法退租(除非发现不可抗力),如遇游戏的风控策略调整导致账号异常,如账号主动提交过人脸识别认证(按交易协议比例赔偿)。
|
|
|
|
2. 账号信息不齐
|
|
租客流需在首次上号后10分钟完成验号,超时则单次以租期已开始计算,此后中断与异常问题由租客自行承担。
|
|
|
|
仅以在首次上号10分钟之前完成查验;
|
|
|
|
未上号马号主与关联等,如果出现异常抢拍后经过时,除押金全额返还后,可能会影响结账比例规则判定。
|
|
|
|
二、账号使用规范
|
|
|
|
3. 切勿使用规制
|
|
账号内绑"绑币"外,其它物品谨慎消耗,送意开货时用品、子弹包、资源包、全能包、合金包。
|
|
|
|
活动赠送或抽奖券及二次充值。
|
|
|
|
若账号因租客违规操作、使用外挂、恶意消耗、转移资产或违反游戏规则造成损失,可能从押金中扣除或进入争议处理,根本扣除额按按违规严重程度而定。
|
|
|
|
4. 禁止转租
|
|
|
|
不可转租、转借或用于任何非订单目的。
|
|
|
|
号主无法输入人脸验证;按交接规则卫按级号号不得修改账号绑定信息或任何影响号主取回账号的内容。
|
|
|
|
三、封禁处理规则
|
|
|
|
5. 账号封禁
|
|
账号封禁判责规则按"按照订单记录、截图证据、聊天记录和双方说明"进行判断,若租客操作符合规则但仍封禁,须按封禁情况审核后按实际损失或押金比例约40%补偿号主。
|
|
|
|
不可转按换现金或按时归还后不予退租,按照平台规则处理退款和赔付。`,
|
|
}
|
|
|
|
const props = defineProps<{
|
|
modelValue: boolean
|
|
config: SystemConfig
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
(e: 'update:modelValue', val: boolean): void
|
|
(e: 'saved'): void
|
|
}>()
|
|
|
|
const submitting = ref(false)
|
|
const description = ref('')
|
|
const draft = ref<PostRentalNotice>(cloneNotice(defaultPostRentalNotice))
|
|
|
|
watch(
|
|
() => props.modelValue,
|
|
val => {
|
|
if (val) {
|
|
draft.value = parsePostRentalNotice(props.config.value)
|
|
description.value = props.config.description || ''
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
)
|
|
|
|
function parsePostRentalNotice(raw: string) {
|
|
const parsed = safeParseJSON(raw, defaultPostRentalNotice)
|
|
return cloneNotice({
|
|
title: readText(parsed?.title, defaultPostRentalNotice.title),
|
|
content: readText(parsed?.content, defaultPostRentalNotice.content),
|
|
})
|
|
}
|
|
|
|
function readText(value: unknown, fallback: string) {
|
|
return typeof value === 'string' && value.trim() ? value : fallback
|
|
}
|
|
|
|
function cloneNotice(value: PostRentalNotice) {
|
|
return JSON.parse(JSON.stringify(value)) as PostRentalNotice
|
|
}
|
|
|
|
function resetDefaults() {
|
|
draft.value = cloneNotice(defaultPostRentalNotice)
|
|
}
|
|
|
|
async function handleSave() {
|
|
submitting.value = true
|
|
try {
|
|
const value = JSON.stringify(draft.value, null, 2)
|
|
await updateSystemConfig(props.config.key, {
|
|
value,
|
|
description: description.value,
|
|
})
|
|
ElMessage.success('租后须知配置已更新')
|
|
emit('saved')
|
|
emit('update:modelValue', false)
|
|
} catch (error) {
|
|
ElMessage.error(readError(error, '保存失败'))
|
|
} finally {
|
|
submitting.value = false
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<el-dialog
|
|
:model-value="modelValue"
|
|
title="编辑租后须知"
|
|
width="720px"
|
|
@update:model-value="emit('update:modelValue', $event)"
|
|
>
|
|
<div class="dialog-body">
|
|
<div class="dialog-header">
|
|
<p class="config-key-label">
|
|
<strong>{{ config.key }}</strong>
|
|
</p>
|
|
<el-button size="small" @click="resetDefaults">恢复默认文本</el-button>
|
|
</div>
|
|
|
|
<section class="notice-editor-card">
|
|
<el-form-item label="标题" class="full-control">
|
|
<el-input v-model="draft.title" placeholder="请输入标题" />
|
|
</el-form-item>
|
|
<el-form-item label="内容正文" class="full-control">
|
|
<el-input
|
|
v-model="draft.content"
|
|
type="textarea"
|
|
:rows="18"
|
|
resize="vertical"
|
|
placeholder="请输入内容正文"
|
|
/>
|
|
</el-form-item>
|
|
</section>
|
|
|
|
<el-form-item label="配置说明" class="desc-item">
|
|
<el-input v-model="description" type="textarea" :rows="3" placeholder="配置说明" />
|
|
</el-form-item>
|
|
</div>
|
|
<template #footer>
|
|
<el-button @click="emit('update:modelValue', false)">取消</el-button>
|
|
<el-button type="primary" :loading="submitting" @click="handleSave">保存</el-button>
|
|
</template>
|
|
</el-dialog>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.dialog-body {
|
|
display: grid;
|
|
gap: 16px;
|
|
max-height: 68vh;
|
|
overflow-y: auto;
|
|
padding-right: 8px;
|
|
}
|
|
|
|
.dialog-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
}
|
|
|
|
.config-key-label {
|
|
margin: 0;
|
|
color: #374151;
|
|
}
|
|
|
|
.notice-editor-card {
|
|
display: grid;
|
|
gap: 12px;
|
|
padding: 14px;
|
|
border: 1px solid #e5e7eb;
|
|
border-radius: 8px;
|
|
background: #f9fafb;
|
|
}
|
|
|
|
.full-control,
|
|
.desc-item {
|
|
margin-bottom: 0;
|
|
}
|
|
</style>
|