You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

676 lines
21 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<script setup>
/**
* name
* usersa0ChunLuyu
* date2022年12月26日 15:06:33
*/
import {
ConfigDeleteAction,
ConfigUpdateAction,
UploadImageAction,
ConfigCreateAction,
ConfigListAction,
$response,
$base64,
$image,
} from '~/api'
import JsonEditorVue from 'json-editor-vue3'
import {h} from "vue";
import {NInput} from 'naive-ui'
onMounted(() => {
ConfigList()
})
const config_active = ref([])
const config_list = ref([])
const ConfigList = async () => {
const response = await ConfigListAction()
$response(response, () => {
config_list.value = response.data.list
})
}
const type_arr = ['', '文字', '图片', '文字数组', '图片数组', 'JSON']
const config_columns = [{
type: 'selection',
multiple: false,
}, {
type: 'expand',
renderExpand: (row) => {
switch (row.type) {
case 1:
return h(
'div',
{
class: ['config_text_wrapper']
},
{
default: () => {
return row.value
}
}
)
case 2:
return h(
'div',
{
class: ['config_image_wrapper']
},
[h(
'div',
{
class: ['config_image_item_wrapper'],
},
[h(
'img',
{
src: $image(row.value_turn)
},
{
default: () => {
}
}
)]
)]
)
case 3:
return h(
'div',
{},
row.value_turn.map((item) => {
return h(
'div',
{
class: ['config_text_wrapper']
},
{
default: () => {
return item
}
}
)
})
)
case 4:
return h(
'div',
{
class: ['config_image_wrapper']
},
row.value_turn.map((item) => {
return h(
'div',
{
class: ['config_image_item_wrapper', 'm-1'],
},
[h(
'img',
{
src: $image(item)
},
{
default: () => {
}
}
)]
)
})
)
case 5:
return h(
NInput,
{
type: "textarea",
disabled: true,
autosize: {minRows: 8},
value: JSON.stringify(row.value_turn, null, 4),
},
{
default: () => {
return row.value
}
}
)
}
}
}, {
title: '名称',
key: 'label'
}, {
title: '类型',
key: 'type',
render(row) {
return type_arr[row.type]
}
}, {
title: '备注',
key: 'remark'
}]
const type_value_arr = ['', '', '', [], [], {}]
const create_show = ref(false)
const create_data_default = {
label: '',
value: '',
value_edit: '',
value_push: '',
type: 1,
remark: '',
}
const create_data = ref(JSON.parse(JSON.stringify(create_data_default)))
const ConfigCreate = async () => {
const response = await ConfigCreateAction({
label: create_data.value.label,
value: [3, 4, 5].indexOf(create_data.value.type) !== -1 ? JSON.stringify(create_data.value.value_edit) : create_data.value.value_edit,
type: create_data.value.type,
remark: create_data.value.remark,
})
$response(response, () => {
window.$message().success(response.message)
create_show.value = false
create_data.value = JSON.parse(JSON.stringify(create_data_default))
ConfigList()
})
}
const createShowClick = () => {
create_data.value = JSON.parse(JSON.stringify(create_data_default))
create_show.value = true
}
const typeChooseUpdate = (e) => {
if (create_show.value) {
create_data.value.value_edit = JSON.parse(JSON.stringify(type_value_arr[e]))
create_data.value.value_push = ''
create_data.value.type = e
} else {
update_data.value.value_edit = JSON.parse(JSON.stringify(type_value_arr[e]))
update_data.value.value_push = ''
update_data.value.type = e
}
}
const addValueClick = () => {
if (create_show.value) {
const push = JSON.parse(JSON.stringify(create_data.value.value_push))
create_data.value.value_push = ''
create_data.value.value_edit.push(push)
} else {
const push = JSON.parse(JSON.stringify(update_data.value.value_push))
update_data.value.value_push = ''
update_data.value.value_edit.push(push)
}
}
const delValueClick = (key) => {
if (create_show.value) {
create_data.value.value_edit.splice(key, 1)
} else {
update_data.value.value_edit.splice(key, 1)
}
}
const update_input_ref = ref(null)
const updateInputRef = (e) => {
update_input_ref.value = e
}
const image_active = ref(-2)
const inputUpdate = async (e) => {
const file = e.target.files[0]
update_input_ref.value.value = null
const base64 = await $base64(file)
const response = await UploadImageAction(base64)
$response(response, () => {
let url = response.data.url
if (create_show.value) {
if (image_active.value === -2) {
create_data.value.value_edit = url
} else if (image_active.value === -1) {
create_data.value.value_edit.push(url)
} else {
create_data.value.value_edit[image_active.value] = url
}
} else {
if (image_active.value === -2) {
update_data.value.value_edit = url
} else if (image_active.value === -1) {
update_data.value.value_edit.push(url)
} else {
update_data.value.value_edit[image_active.value] = url
}
}
})
}
const updateImageClick = (key) => {
image_active.value = key
update_input_ref.value.click()
}
const update_show = ref(false)
const update_data_default = {
id: 0,
label: '',
value: '',
value_edit: '',
value_push: '',
type: 1,
remark: '',
}
const update_data = ref(JSON.parse(JSON.stringify(update_data_default)))
const ConfigUpdate = async () => {
const response = await ConfigUpdateAction({
config_id: update_data.value.id,
label: update_data.value.label,
value: [3, 4, 5].indexOf(update_data.value.type) !== -1 ? JSON.stringify(update_data.value.value_edit) : update_data.value.value_edit,
type: update_data.value.type,
remark: update_data.value.remark,
})
$response(response, () => {
window.$message().success(response.message)
update_show.value = false
update_data.value = JSON.parse(JSON.stringify(update_data_default))
ConfigList()
})
}
const updateShowClick = () => {
if (config_active.value.length !== 1) return window.$message().error('请选择一个配置')
update_data.value = JSON.parse(JSON.stringify(update_data_default))
for (let i = 0; i < config_list.value.length; i++) {
if (config_active.value[0] === config_list.value[i].id) {
update_data.value = {
id: config_list.value[i].id,
label: config_list.value[i].label,
value: config_list.value[i].value,
value_edit: config_list.value[i].value_turn,
value_push: '',
type: config_list.value[i].type,
remark: config_list.value[i].remark,
}
update_show.value = true
return
}
}
}
const deleteImageClick = (key) => {
if (create_show.value) {
if (key === -2) {
create_data.value.value_edit = ''
} else {
create_data.value.value_edit.splice(key, 1)
}
} else {
if (key === -2) {
update_data.value.value_edit = ''
} else {
update_data.value.value_edit.splice(key, 1)
}
}
}
const delete_show = ref(false)
const deleteShowClick = () => {
if (config_active.value.length !== 1) return window.$message().error('请选择一个配置')
delete_show.value = true
}
const ConfigDelete = async () => {
const response = await ConfigDeleteAction(config_active.value[0])
$response(response, () => {
window.$message().success(response.message)
delete_show.value = false
config_active.value = []
ConfigList()
})
}
</script>
<template>
<div>
<n-modal v-model:show="delete_show" preset="card" :style="{width: '400px'}" title="删除确认" :auto-focus="false"
:bordered="false">
<div>
<n-alert title="删除不可恢复且可能会引发严重BUG" type="error">
<template #icon>
<n-icon>
<Icon type="alarm"></Icon>
</n-icon>
</template>
</n-alert>
<n-alert mt-2 title="删除不可恢复且可能会引发严重BUG" type="error">
<template #icon>
<n-icon>
<Icon type="alarm"></Icon>
</n-icon>
</template>
</n-alert>
<n-alert mt-2 title="删除不可恢复且可能会引发严重BUG" type="error">
<template #icon>
<n-icon>
<Icon type="alarm"></Icon>
</n-icon>
</template>
</n-alert>
<n-space mt-2 justify="center">
<n-button @click="ConfigDelete()" type="info">确定</n-button>
<n-button @click="delete_show = false">取消</n-button>
</n-space>
</div>
</n-modal>
<n-modal v-model:show="update_show" preset="card" :style="{width: '1000px'}" title="修改" :auto-focus="false"
:bordered="false">
<div>
<n-space align="center">
<n-tag>
<div class="form_tag_wrapper">名称</div>
</n-tag>
<n-input class="form_input_wrapper" v-model:value="update_data.label"></n-input>
</n-space>
<n-space mt-2 align="center">
<n-tag>
<div class="form_tag_wrapper">类型</div>
</n-tag>
<n-radio-group v-model:value="update_data.type" @update:value="typeChooseUpdate" name="type_radio">
<n-space>
<n-radio :value="1">文字</n-radio>
<n-radio :value="2">图片</n-radio>
<n-radio :value="3">文字数组</n-radio>
<n-radio :value="4">图片数组</n-radio>
<n-radio :value="5">JSON</n-radio>
</n-space>
</n-radio-group>
</n-space>
<n-space mt-2>
<n-tag mt-1>
<div class="form_tag_wrapper">内容</div>
</n-tag>
<template v-if="update_data.type === 1">
<n-input class="form_input_wrapper" v-model:value="update_data.value_edit"></n-input>
</template>
<template v-if="update_data.type === 2">
<div class="config_image_wrapper">
<div class="config_image_item_wrapper" m-1>
<span v-if="!update_data.value_edit">暂无图片</span>
<div class="config_image_cover_wrapper">
<div class="config_image_cover_upload_wrapper" cursor-pointer @click="updateImageClick(-2)">
<Icon type="upload-three"></Icon>
</div>
<div v-if="!!update_data.value_edit" cursor-pointer class="config_image_cover_delete_wrapper"
@click="deleteImageClick(-2)">
<Icon type="delete-one"></Icon>
</div>
</div>
<img v-if="!!update_data.value_edit" :src="$image(update_data.value_edit)" alt="">
</div>
</div>
</template>
<template v-if="update_data.type === 3">
<n-scrollbar style="max-height: 500px">
<n-space mb-2 v-for="(i,k) in update_data.value_edit" :key="k" align="center">
<n-input class="form_input_wrapper" v-model:value="update_data.value_edit[k]"></n-input>
<n-button @click="delValueClick(k)" quaternary circle type="error">
<template #icon>
<n-icon>
<Icon type="minus"></Icon>
</n-icon>
</template>
</n-button>
</n-space>
<n-space align="center">
<n-input class="form_input_wrapper" v-model:value="update_data.value_push"></n-input>
<n-button @click="addValueClick()" quaternary circle type="info">
<template #icon>
<n-icon>
<Icon type="plus"></Icon>
</n-icon>
</template>
</n-button>
</n-space>
</n-scrollbar>
</template>
<template v-if="update_data.type === 4">
<n-scrollbar style="max-height: 500px">
<div class="config_image_wrapper">
<div v-for="(i,k) in update_data.value_edit" :key="k"
class="config_image_item_wrapper" m-1 cursor-pointer>
<div class="config_image_cover_wrapper">
<div class="config_image_cover_upload_wrapper" @click="updateImageClick(k)">
<Icon type="upload-three"></Icon>
</div>
<div class="config_image_cover_delete_wrapper" @click="deleteImageClick(k)">
<Icon type="delete-one"></Icon>
</div>
</div>
<img :src="$image(i)" alt="">
</div>
<div @click="updateImageClick(-1)" class="config_image_item_wrapper" m-1 cursor-pointer>上传图片</div>
</div>
</n-scrollbar>
</template>
<template v-if="update_data.type === 5">
<JsonEditorVue style="width: 840px;height: 500px;" v-model="update_data.value_edit" language="zh-CN"
:modeList="[]"></JsonEditorVue>
</template>
</n-space>
<n-space mt-2 align="center">
<n-tag>
<div class="form_tag_wrapper">备注</div>
</n-tag>
<n-input class="form_input_wrapper" v-model:value="update_data.remark"></n-input>
</n-space>
<n-space mt-2>
<n-button @click="ConfigUpdate()" type="info">确定</n-button>
</n-space>
</div>
</n-modal>
<n-modal v-model:show="create_show" preset="card" :style="{width: '1000px'}" title="新建" :auto-focus="false"
:bordered="false">
<div>
<n-space align="center">
<n-tag>
<div class="form_tag_wrapper">名称</div>
</n-tag>
<n-input class="form_input_wrapper" v-model:value="create_data.label"></n-input>
</n-space>
<n-space mt-2 align="center">
<n-tag>
<div class="form_tag_wrapper">类型</div>
</n-tag>
<n-radio-group v-model:value="create_data.type" @update:value="typeChooseUpdate" name="type_radio">
<n-space>
<n-radio :value="1">文字</n-radio>
<n-radio :value="2">图片</n-radio>
<n-radio :value="3">文字数组</n-radio>
<n-radio :value="4">图片数组</n-radio>
<n-radio :value="5">JSON</n-radio>
</n-space>
</n-radio-group>
</n-space>
<n-space mt-2>
<n-tag mt-1>
<div class="form_tag_wrapper">内容</div>
</n-tag>
<template v-if="create_data.type === 1">
<n-input class="form_input_wrapper" v-model:value="create_data.value_edit"></n-input>
</template>
<template v-if="create_data.type === 2">
<div class="config_image_wrapper">
<div class="config_image_item_wrapper" m-1>
<span v-if="!create_data.value_edit">暂无图片</span>
<div class="config_image_cover_wrapper">
<div class="config_image_cover_upload_wrapper" cursor-pointer @click="updateImageClick(-2)">
<Icon type="upload-three"></Icon>
</div>
<div v-if="!!create_data.value_edit" cursor-pointer class="config_image_cover_delete_wrapper"
@click="deleteImageClick(-2)">
<Icon type="delete-one"></Icon>
</div>
</div>
<img v-if="!!create_data.value_edit" :src="$image(create_data.value_edit)" alt="">
</div>
</div>
</template>
<template v-if="create_data.type === 3">
<n-scrollbar style="max-height: 500px">
<n-space mb-2 v-for="(i,k) in create_data.value_edit" :key="k" align="center">
<n-input class="form_input_wrapper" v-model:value="create_data.value_edit[k]"></n-input>
<n-button @click="delValueClick(k)" quaternary circle type="error">
<template #icon>
<n-icon>
<Icon type="minus"></Icon>
</n-icon>
</template>
</n-button>
</n-space>
<n-space align="center">
<n-input class="form_input_wrapper" v-model:value="create_data.value_push"></n-input>
<n-button @click="addValueClick()" quaternary circle type="info">
<template #icon>
<n-icon>
<Icon type="plus"></Icon>
</n-icon>
</template>
</n-button>
</n-space>
</n-scrollbar>
</template>
<template v-if="create_data.type === 4">
<n-scrollbar style="max-height: 500px">
<div class="config_image_wrapper">
<div v-for="(i,k) in create_data.value_edit" :key="k" @click="updateImageClick(k)"
class="config_image_item_wrapper" m-1 cursor-pointer>
<div class="config_image_cover_wrapper">
<div class="config_image_cover_upload_wrapper" @click="updateImageClick(k)">
<Icon type="upload-three"></Icon>
</div>
<div class="config_image_cover_delete_wrapper" @click="deleteImageClick(k)">
<Icon type="delete-one"></Icon>
</div>
</div>
<img :src="$image(i)" alt="">
</div>
<div @click="updateImageClick(-1)" class="config_image_item_wrapper" m-1 cursor-pointer>上传图片</div>
</div>
</n-scrollbar>
</template>
<template v-if="create_data.type === 5">
<JsonEditorVue style="width: 840px;height: 500px;" v-model="create_data.value_edit" language="zh-CN"
:modeList="[]"></JsonEditorVue>
</template>
</n-space>
<n-space mt-2 align="center">
<n-tag>
<div class="form_tag_wrapper">备注</div>
</n-tag>
<n-input class="form_input_wrapper" v-model:value="create_data.remark"></n-input>
</n-space>
<n-space mt-2>
<n-button @click="ConfigCreate()" type="info">确定</n-button>
</n-space>
</div>
</n-modal>
<input class="upload_input_wrapper" accept="image/*" @change="inputUpdate" type="file" :ref="updateInputRef">
<n-card title="后台配置">
<div>
<n-space>
<n-button @click="createShowClick()" type="success">新建</n-button>
<n-button @click="deleteShowClick()" type="error">删除</n-button>
<n-button @click="updateShowClick()" type="info">修改</n-button>
</n-space>
<n-alert mt-2 title="在修改和删除前请确保您已经充分理解该配置的含义及用法盲目修改或删除可能会引发严重BUG"
type="error">
<template #icon>
<n-icon>
<Icon type="alarm"></Icon>
</n-icon>
</template>
</n-alert>
<n-data-table mt-2 v-model:checked-row-keys="config_active"
:columns="config_columns"
:row-key="row=>row.id" :data="config_list"/>
</div>
</n-card>
</div>
</template>
<style>
a.jsoneditor-poweredBy {
font-size: 8pt;
position: absolute;
right: 0;
top: 0;
display: none;
}
.config_text_wrapper {
text-align: center;
}
.config_image_wrapper {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
max-width: 700px;
margin: 0 auto;
}
.config_image_item_wrapper {
width: 200px;
height: 200px;
display: table-cell;
vertical-align: middle;
text-align: center;
line-height: 200px;
background: #00000010;
position: relative;
}
.config_image_item_wrapper img {
width: auto;
height: auto;
max-width: 100%;
max-height: 100%;
position: absolute;
z-index: 1;
left: 50%;
bottom: 0;
right: 0;
top: 50%;
transform: translate(-50%, -50%);
}
</style>
<style scoped>
.config_image_cover_upload_wrapper {
width: 50%;
background: #5e92ff50;
}
.config_image_cover_upload_wrapper:hover {
background: #5e92ff70;
}
.config_image_cover_delete_wrapper {
width: 50%;
background: #fd606050;
}
.config_image_cover_delete_wrapper:hover {
background: #fd606070;
}
.config_image_cover_wrapper {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: flex;
z-index: 2;
opacity: 0;
justify-content: center;
}
.config_image_cover_wrapper:hover {
opacity: 1;
}
.upload_input_wrapper {
width: 0px;
height: 0px;
opacity: 0;
}
</style>
<route>
{"meta":{"title":"后台配置"}}
</route>