个人设置、系统设置
This commit is contained in:
parent
3a7c381580
commit
18d128b84c
117
src/components/icon/picker.vue
Normal file
117
src/components/icon/picker.vue
Normal file
@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<n-popover :trigger="trigger" v-model:visible="visible">
|
||||
<template #trigger>
|
||||
<slot name="iconSelect"></slot>
|
||||
</template>
|
||||
<n-input v-model:value="searchValue" placeholder="输入英文关键词进行搜索" @change="filterIcon" />
|
||||
<div class="icon-box" style="width: 400px;">
|
||||
<div v-for="(item, index) in iconArr" :key="index" @click="handleClick(item)" class="icon-content"
|
||||
:style="{ background: icon === item ? '#268961' : '' }">
|
||||
<component :is="iconComponent(item)" />
|
||||
</div>
|
||||
</div>
|
||||
</n-popover>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, watch } from 'vue'
|
||||
import * as VueIcon from '@vicons/antd';
|
||||
import { renderIcon } from '@/utils';
|
||||
export default defineComponent({
|
||||
|
||||
name: "IconPicker",
|
||||
props: {
|
||||
|
||||
icon: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
//自定义触发方式
|
||||
trigger: {
|
||||
|
||||
type: String,
|
||||
default: 'click',
|
||||
validator: function (value) {
|
||||
|
||||
return ['click', 'hover', 'focus'].indexOf(value) !== -1
|
||||
}
|
||||
}
|
||||
},
|
||||
setup(props, context) {
|
||||
const icons = Object.keys(VueIcon)
|
||||
const iconArr = ref(icons)
|
||||
const visible = ref<boolean>(false)
|
||||
const searchValue = ref('')
|
||||
|
||||
const handleClick = (icon) => {
|
||||
|
||||
context.emit('update:icon', icon)
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 进行搜索过滤
|
||||
*/
|
||||
const filterIcon = () => {
|
||||
|
||||
if (searchValue.value) {
|
||||
iconArr.value = icons.filter(item => item.toLowerCase().includes(searchValue.value.toLowerCase()))
|
||||
} else {
|
||||
iconArr.value = icons;
|
||||
}
|
||||
}
|
||||
const iconComponent = (icon) => {
|
||||
const IconComponent = renderIcon(VueIcon[icon]);
|
||||
return IconComponent;
|
||||
}
|
||||
|
||||
watch(visible, () => {
|
||||
|
||||
searchValue.value = ''
|
||||
iconArr.value = icons
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
visible,
|
||||
icons,
|
||||
iconArr,
|
||||
handleClick,
|
||||
searchValue,
|
||||
filterIcon,
|
||||
iconComponent
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.icon-box {
|
||||
|
||||
overflow: auto;
|
||||
font-size: 20px;
|
||||
width: 250px;
|
||||
height: 230px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
align-content: flex-start;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.icon-content {
|
||||
|
||||
width: 45px;
|
||||
height: 40px;
|
||||
margin: 5px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #ccc
|
||||
}
|
||||
|
||||
.icon-content:hover {
|
||||
|
||||
background: #1890ff;
|
||||
}
|
||||
</style>
|
||||
66
src/components/numberInput/index.vue
Normal file
66
src/components/numberInput/index.vue
Normal file
@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<n-input
|
||||
v-model:value="inputValue"
|
||||
:placeholder="placeholder"
|
||||
allow-clear
|
||||
@blur="inputBlur"
|
||||
:max-length="maxlength"
|
||||
@change="inputF"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {computed} from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
default: ""
|
||||
},
|
||||
maxlength: {
|
||||
default: 50
|
||||
},
|
||||
zh: {
|
||||
default: false
|
||||
},
|
||||
isMax: {
|
||||
default: false
|
||||
},
|
||||
maxNum:{
|
||||
default: 0
|
||||
},
|
||||
placeholder:{
|
||||
default: '请输入'
|
||||
},
|
||||
});
|
||||
|
||||
const inputF = (value) =>{
|
||||
console.log(value)
|
||||
let filterValue=value.replace(/[^0-9]/g,'')?(props.zh?parseInt(value.replace(/[^0-9]/g,'')):value.replace(/[^0-9]/g,'')):''
|
||||
if(props.isMax){
|
||||
if(!props.maxNum&&filterValue){
|
||||
filterValue=0
|
||||
}else if(props.maxNum&&filterValue&&filterValue> props.maxNum){
|
||||
filterValue=props.maxNum
|
||||
}
|
||||
}
|
||||
inputValue.value=filterValue
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'update:modelValue', value: any): void,
|
||||
(event: 'blur'): void,
|
||||
}>()
|
||||
|
||||
const inputBlur = ()=>{
|
||||
emit('blur')
|
||||
}
|
||||
|
||||
const inputValue = computed({
|
||||
get() {
|
||||
return props.modelValue
|
||||
},
|
||||
set(value) {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@ -4,11 +4,13 @@
|
||||
*/
|
||||
import { App } from 'vue';
|
||||
import { PageWrapper, PageFooter } from '@/components/Page';
|
||||
import NumberInput from '@/components/numberInput/index.vue';
|
||||
import { basicModal } from '@/components/Modal';
|
||||
import { Authority } from '@/components/Authority';
|
||||
|
||||
export function setupCustomComponents(app: App) {
|
||||
app.component('PageWrapper', PageWrapper);
|
||||
app.component('NumberInput', NumberInput);
|
||||
app.component('basicModal', basicModal);
|
||||
app.component('PageFooter', PageFooter);
|
||||
app.component('Authority', Authority);
|
||||
|
||||
@ -1,71 +0,0 @@
|
||||
<template>
|
||||
<n-grid cols="1 s:1 m:1 l:4 xl:4 2xl:4" responsive="screen">
|
||||
<n-grid-item>
|
||||
<n-form :label-width="80" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="昵称" path="name">
|
||||
<n-input v-model:value="formValue.name" placeholder="请输入昵称" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="邮箱" path="email">
|
||||
<n-input placeholder="请输入邮箱" v-model:value="formValue.email" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="联系电话" path="mobile">
|
||||
<n-input placeholder="请输入联系电话" v-model:value="formValue.mobile" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="联系地址" path="address">
|
||||
<n-input v-model:value="formValue.address" type="textarea" placeholder="请输入联系地址" />
|
||||
</n-form-item>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">更新基本信息</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import { FormRules, useMessage } from 'naive-ui';
|
||||
|
||||
const rules: FormRules = {
|
||||
name: {
|
||||
required: true,
|
||||
message: '请输入昵称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
email: {
|
||||
required: true,
|
||||
message: '请输入邮箱',
|
||||
trigger: 'blur',
|
||||
},
|
||||
mobile: {
|
||||
required: true,
|
||||
message: '请输入联系电话',
|
||||
trigger: 'input',
|
||||
},
|
||||
};
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
|
||||
const formValue = reactive({
|
||||
name: '',
|
||||
mobile: '',
|
||||
email: '',
|
||||
address: '',
|
||||
});
|
||||
|
||||
function formSubmit() {
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
message.success('验证成功');
|
||||
} else {
|
||||
message.error('验证失败,请填写完整信息');
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
241
src/views/setting/configWeb/BasicSetting.vue
Normal file
241
src/views/setting/configWeb/BasicSetting.vue
Normal file
@ -0,0 +1,241 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-form label-width="85px" :model="formData" ref="formRef">
|
||||
<n-form-item
|
||||
v-for="(item, index) in configItemList.filter((item) => item.type != 'hidden')"
|
||||
:key="index"
|
||||
:label="`${item.name}:`"
|
||||
:path="item.code"
|
||||
label-placement="left"
|
||||
>
|
||||
<template
|
||||
v-if="
|
||||
item.type == 'text' ||
|
||||
item.type == 'readonly' ||
|
||||
item.type == 'textarea' ||
|
||||
item.type == 'password'
|
||||
"
|
||||
>
|
||||
<n-input
|
||||
v-model:value="formData[item.code]"
|
||||
:placeholder="`请输入${item.name}`"
|
||||
:type="
|
||||
item.type == 'textarea' ? 'textarea' : item.type == 'password' ? 'password' : ''
|
||||
"
|
||||
:readonly="item.type == 'readonly'"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="item.type == 'number'">
|
||||
<n-input-number v-model:value="formData[item.code]" placeholder="请输入" />
|
||||
</template>
|
||||
<!-- <template v-else-if="item.type=='icon'">
|
||||
<IconPicker class="flex-1" v-model="formData[item.code]"/>
|
||||
</template> -->
|
||||
<template v-else-if="item.type == 'radio'">
|
||||
<n-radio-group v-model:value="formData[item.code]" :path="item.code">
|
||||
<n-radio v-for="(value, key) in item.param" :value="key" :key="key">
|
||||
{{ value }}
|
||||
</n-radio>
|
||||
</n-radio-group>
|
||||
</template>
|
||||
<template v-else-if="item.type == 'checkbox'">
|
||||
<n-checkbox-group v-model:value="formData[item.code]" :path="item.code">
|
||||
<n-checkbox :value="key" :key="key" v-for="(value, key) in item.param">{{
|
||||
value
|
||||
}}</n-checkbox>
|
||||
</n-checkbox-group>
|
||||
</template>
|
||||
<template v-else-if="item.type == 'select' || item.type == 'selects'">
|
||||
<n-select
|
||||
v-model:value="formData[item.code]"
|
||||
:multiple="item.type == 'selects' ? true: false"
|
||||
:options="item.param"
|
||||
>
|
||||
</n-select>
|
||||
</template>
|
||||
<template v-else-if="item.type == 'date' || item.type == 'datetime'">
|
||||
<n-date-picker
|
||||
:type="item.type"
|
||||
:placeholder="`请选择${item.name}`"
|
||||
v-model:value="formData[item.code]"
|
||||
style="width: 100%"
|
||||
:value-format="item.type == 'date' ? 'yyyy-MM-dd' : 'yyyy-MM-dd HH:mm:ss'"
|
||||
:format="item.type == 'date' ? 'yyyy-MM-dd' : 'yyyy-MM-dd HH:mm:ss'"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="item.type == 'image'">
|
||||
<UploadImg
|
||||
:fileType="['image/jpeg', 'image/png', 'image/jpg', 'image/gif']"
|
||||
name="setting"
|
||||
:fileSize="200"
|
||||
v-model:image-url="formData[item.code]"
|
||||
>
|
||||
<template #tip>支持扩展名: jpg png jpeg;文件大小不超过200M</template>
|
||||
</UploadImg>
|
||||
</template>
|
||||
<template v-else-if="item.type == 'images'">
|
||||
<UploadImgs
|
||||
@upload="fileUploadImgs"
|
||||
file-type=".jpeg,.png,.jpg,.gif"
|
||||
name="setting"
|
||||
:fileSize="200"
|
||||
:multiple="true"
|
||||
:fileLists="item.filePath"
|
||||
:z-index="index"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="item.type == 'file'">
|
||||
<UploadFile
|
||||
@upload="fileUploadFile"
|
||||
file-type=".xlsx.xls.doc.docx"
|
||||
name="setting"
|
||||
:fileLists="formData[item.code] ? [{ name: item.fileName, url: item.filePath }] : []"
|
||||
:z-index="index"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="item.type == 'files'">
|
||||
<UploadFile
|
||||
@upload="fileUploadFiles"
|
||||
file-type=".xlsx.xls.doc.docx"
|
||||
name="setting"
|
||||
:multiple="true"
|
||||
:fileLists="item.filePath"
|
||||
:z-index="index"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="item.type == 'ueditor'">
|
||||
<Editor ref="editorRef" :height="fwbHeight" class="flex-1" name="config" />
|
||||
</template>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<div class="submit-btn">
|
||||
<n-button type="primary" @click="handleSubmit" v-perm="['sys:configWeb:save']"
|
||||
>更新系统设置</n-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, onMounted, nextTick } from 'vue';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import Editor from '@/components/Editor/tinymce.vue';
|
||||
import UploadImg from '@/components/Upload/Image.vue';
|
||||
import UploadImgs from '@/components/Upload/Images.vue';
|
||||
import UploadFile from '@/components/Upload/file.vue';
|
||||
import { updateWeb } from '@/api/setting/web';
|
||||
|
||||
/**
|
||||
* 定义接收的参数
|
||||
*/
|
||||
const props = defineProps({
|
||||
dataList: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: [],
|
||||
},
|
||||
activeName: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* 定义参数变量
|
||||
*/
|
||||
const message = useMessage();
|
||||
const editorRef = ref();
|
||||
const formRef = ref();
|
||||
const fwbHeight = document.body.clientHeight - 400;
|
||||
const formData = reactive({});
|
||||
const configItemList = ref([]);
|
||||
const emit = defineEmits(['success']);
|
||||
|
||||
/**
|
||||
* 执行提交表单
|
||||
*/
|
||||
const handleSubmit = async () => {
|
||||
await formRef.value?.validate();
|
||||
let ueditorIndex = 0;
|
||||
configItemList.value.map((item) => {
|
||||
if (item.type == 'ueditor') {
|
||||
formData[item.code] = editorRef.value[ueditorIndex].myValue;
|
||||
ueditorIndex++;
|
||||
}
|
||||
});
|
||||
console.log(formData);
|
||||
await updateWeb(formData);
|
||||
message.success('更新成功');
|
||||
emit('success', props.activeName);
|
||||
};
|
||||
|
||||
/**
|
||||
* 上传图片文件
|
||||
* @param list 列表
|
||||
* @param index 索引
|
||||
*/
|
||||
const fileUploadImgs = (list: any, index: any) => {
|
||||
const code = configItemList.value[index].code;
|
||||
formData[code] = [];
|
||||
configItemList.value[index].filePath = [];
|
||||
list.map((item) => {
|
||||
formData[code].push(item.filePath);
|
||||
configItemList.value[index].filePath.push({ filePath: item.filePath });
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
* @param filePath 文件路径
|
||||
* @param fileName 文件名称
|
||||
* @param index 索引
|
||||
*/
|
||||
const fileUploadFile = async (filePath: any, fileName: any, index: any) => {
|
||||
const code = configItemList.value[index].code;
|
||||
formData[code] = filePath ? `${fileName}|${filePath}` : '';
|
||||
configItemList.value[index].filePath = filePath;
|
||||
configItemList.value[index].fileName = fileName;
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量上传文件
|
||||
* @param list 列表
|
||||
* @param index 索引
|
||||
*/
|
||||
const fileUploadFiles = (list: any, index: any) => {
|
||||
const code = configItemList.value[index].code;
|
||||
configItemList.value[index].filePath = [];
|
||||
formData[code] = [];
|
||||
list.map((item) => {
|
||||
formData[code].push(`${item.name}|${item.url}`);
|
||||
configItemList.value[index].filePath.push({ name: item.name, url: item.url });
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 钩子函数
|
||||
*/
|
||||
onMounted(() => {
|
||||
configItemList.value = JSON.parse(JSON.stringify(props.dataList));
|
||||
nextTick(() => {
|
||||
let ueditorIndex = 0;
|
||||
configItemList.value.map((item) => {
|
||||
formData[item.code] = item.value;
|
||||
if (item.type == 'ueditor') {
|
||||
if (editorRef.value) {
|
||||
editorRef.value[ueditorIndex].myValue = item.value;
|
||||
ueditorIndex++;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.submit-btn {
|
||||
position: fixed;
|
||||
bottom: 50px;
|
||||
right: 4%;
|
||||
}
|
||||
</style>
|
||||
116
src/views/setting/configWeb/index.vue
Normal file
116
src/views/setting/configWeb/index.vue
Normal file
@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<PageWrapper>
|
||||
<n-card shadow="never" size="small" class="proCard tabsCard">
|
||||
<n-tabs v-model="activeName" v-if="tabData.length > 0">
|
||||
<n-tab-pane
|
||||
:name="item.configName"
|
||||
:tab="item.configName"
|
||||
v-for="(item, index) in tabData"
|
||||
:key="index"
|
||||
>
|
||||
<BasicSetting
|
||||
:dataList="item.dataList"
|
||||
v-if="activeName == item.configName"
|
||||
@success="getReshTabData"
|
||||
:activeName="activeName"
|
||||
/>
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</n-card>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { getWebInfo } from '@/api/setting/web';
|
||||
import { PageWrapper } from '@/components/Page';
|
||||
import BasicSetting from './BasicSetting.vue';
|
||||
const activeName = ref();
|
||||
const tabData = ref([]);
|
||||
|
||||
/**
|
||||
* 获取TAB数据
|
||||
*/
|
||||
const getTabData = async (name) => {
|
||||
let res = await getWebInfo();
|
||||
res.map((item) => {
|
||||
item.dataList.map((sub) => {
|
||||
if (sub.type == 'checkbox' || sub.type == 'selects') {
|
||||
const values = sub.value.split(',');
|
||||
sub.value = values;
|
||||
console.log(values)
|
||||
}
|
||||
if (sub.type == 'select' || sub.type == 'selects') {
|
||||
const arrs = Object.entries(sub.param).map(([key, value]) => ({ label: value, value:key }));
|
||||
sub.param = arrs
|
||||
console.log(arrs)
|
||||
}
|
||||
if (sub.type == 'images') {
|
||||
sub.filePath = [];
|
||||
sub.value = [];
|
||||
if (sub.valueList && sub.valueList.length) {
|
||||
sub.valueList.map((path) => {
|
||||
sub.filePath.push({ url:path,filePath: path });
|
||||
sub.value.push(path);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (sub.type == 'file') {
|
||||
let files = sub.value?.split('|');
|
||||
sub.fileName = files[0];
|
||||
sub.filePath = files[1];
|
||||
}
|
||||
if (sub.type == 'files') {
|
||||
sub.filePath = [];
|
||||
sub.value = [];
|
||||
if (sub.valueList && sub.valueList.length) {
|
||||
sub.valueList.map((path) => {
|
||||
let files = path.split('|');
|
||||
sub.filePath.push({ name: files[0], url: files[1] });
|
||||
sub.value.push(`${files[0]}|${files[1]}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
tabData.value = res;
|
||||
activeName.value = name ? name : tabData.value[0].configName;
|
||||
};
|
||||
|
||||
/**
|
||||
* 刷新TAB数据
|
||||
*/
|
||||
const getReshTabData = (name) => {
|
||||
getTabData(name);
|
||||
};
|
||||
|
||||
/**
|
||||
* 钩子函数
|
||||
*/
|
||||
onMounted(() => {
|
||||
getTabData();
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.thing-cell {
|
||||
margin: 0 -16px 10px;
|
||||
padding: 5px 16px;
|
||||
|
||||
&:hover {
|
||||
background: #f3f3f3;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.thing-cell-on {
|
||||
background: #f0faff;
|
||||
color: #165dff;
|
||||
|
||||
:deep(.n-thing-main .n-thing-header .n-thing-header__title) {
|
||||
color: #165dff;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #f0faff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
120
src/views/setting/profile/BasicSetting.vue
Normal file
120
src/views/setting/profile/BasicSetting.vue
Normal file
@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<n-form :label-width="80" :model="formData" ref="formRef" label-placement="left">
|
||||
<div class="flex">
|
||||
<n-form-item label="名称" path="realname" class="flex-1"
|
||||
:rule="{ required: true, message: '请输入名称', trigger: 'blur' }">
|
||||
<n-input v-model:value="formData.realname" placeholder="请输入名称" clearable />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="性别" path="sex" class="flex-1">
|
||||
<n-radio-group v-model:value="formData.gender" name="gender">
|
||||
<n-radio :value="1">男</n-radio>
|
||||
<n-radio :value="2">女</n-radio>
|
||||
<n-radio :value="3">保密</n-radio>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<n-form-item label="手机号码" path="mobile" class="flex-1" :rule="[
|
||||
{ required: true, message: '请输入手机号码', trigger: 'blur' },
|
||||
{ validator: rule.validatePhone, trigger: 'blur' },
|
||||
]">
|
||||
<n-input v-model:value="formData.mobile" placeholder="请输入手机号码" clearable />
|
||||
</n-form-item>
|
||||
<n-form-item label="邮箱地址" path="email" class="flex-1" :rule="[
|
||||
{ required: true, message: '请输入邮箱地址', trigger: 'blur' },
|
||||
{ type: 'email', message: '请输入正确邮箱地址', trigger: 'blur' },
|
||||
]">
|
||||
<n-input v-model:value="formData.email" placeholder="请输入邮箱地址" clearable />
|
||||
</n-form-item>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<n-form-item label="所属区域" class="flex-1" path="city"
|
||||
:rule="{ type: 'array', required: true, message: '请选择所属区域', trigger: 'change' }">
|
||||
<chinaArea style="width: 100%" :type="4" v-model="formData.city" />
|
||||
</n-form-item>
|
||||
<n-form-item label="详细地址" class="flex-1" path="address"
|
||||
:rule="{ required: true, message: '请输入详细地址', trigger: 'blur' }">
|
||||
<n-input v-model:value="formData.address" placeholder="请输入详细地址" clearable />
|
||||
</n-form-item>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<n-form-item label="简介" path="intro" class="flex-1">
|
||||
<n-input v-model:value="formData.intro" type="textarea" placeholder="请输入简介" clearable />
|
||||
</n-form-item>
|
||||
<n-form-item label="备注" path="note" class="flex-1">
|
||||
<n-input v-model:value="formData.note" type="textarea" placeholder="请输入备注" clearable />
|
||||
</n-form-item>
|
||||
</div>
|
||||
<n-form-item label="头像" path="avatar" :rule="{ required: true, message: '请上传头像', trigger: 'blur' }">
|
||||
<UploadImg @change-file-name="(name) => (formData.avatarName = name)"
|
||||
:fileType="['image/jpeg', 'image/png', 'image/jpg', 'image/gif']" name="user" :fileSize="200"
|
||||
v-model:image-url="formData.avatar">
|
||||
<template #tip>支持扩展名: jpg png jpeg;文件大小不超过200M</template>
|
||||
</UploadImg>
|
||||
</n-form-item>
|
||||
<n-form-item style="margin-left: 85px;" v-perm="['sys:profile:update']">
|
||||
<n-space>
|
||||
<n-button :loading="subLoading" type="primary" @click="submit">更新基本信息</n-button>
|
||||
</n-space>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, onMounted } from 'vue';
|
||||
import { FormRules, useMessage } from 'naive-ui';
|
||||
import { rule } from '@/utils/validate';
|
||||
import chinaArea from '@/components/ChinaArea/index.vue';
|
||||
import UploadImg from '@/components/Upload/Image.vue';
|
||||
import { message } from 'naive-ui';
|
||||
import { useLockFn } from '@/utils/useLockFn';
|
||||
import { getUserInfo } from '@/api/system/user';
|
||||
import { updateProfile } from '@/api/setting/profile';
|
||||
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
/**
|
||||
* 定义表单参数
|
||||
*/
|
||||
const formData = reactive({
|
||||
realname: '',
|
||||
gender: '',
|
||||
avatar: '',
|
||||
mobile: '',
|
||||
email: '',
|
||||
city: [],
|
||||
address: '',
|
||||
intro: '',
|
||||
note: '',
|
||||
avatarName: '',
|
||||
});
|
||||
|
||||
/**
|
||||
* 执行提交表单
|
||||
*/
|
||||
const handleSubmit = async () => {
|
||||
await formRef.value?.validate();
|
||||
await updateProfile(formData);
|
||||
message.success('更新成功');
|
||||
};
|
||||
const { isLock: subLoading, lockFn: submit } = useLockFn(handleSubmit);
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*/
|
||||
const getUserDetail = async () => {
|
||||
const data = await getUserInfo();
|
||||
for (const key in formData) {
|
||||
if (data[key] != null && data[key] != undefined) {
|
||||
formData[key] = data[key];
|
||||
}
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 钩子函数
|
||||
*/
|
||||
onMounted(() => {
|
||||
getUserDetail();
|
||||
});
|
||||
</script>
|
||||
@ -5,7 +5,6 @@
|
||||
<n-tab-pane name="basic" tab="基本设置">
|
||||
<BasicSetting />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="safety" tab="安全设置"><SafetySetting /></n-tab-pane>
|
||||
</n-tabs>
|
||||
</n-card>
|
||||
</PageWrapper>
|
||||
@ -1,114 +0,0 @@
|
||||
<template>
|
||||
<n-grid cols="1 s:1 m:1 l:4 xl:4 2xl:4" responsive="screen">
|
||||
<n-grid-item>
|
||||
<n-form :label-width="80" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="网站名称" path="name">
|
||||
<n-input v-model:value="formValue.name" placeholder="请输入网站名称" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="备案编号" path="icpCode">
|
||||
<n-input placeholder="请输入备案编号" v-model:value="formValue.icpCode" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="联系电话" path="mobile">
|
||||
<n-input placeholder="请输入联系电话" v-model:value="formValue.mobile" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="联系地址" path="address">
|
||||
<n-input v-model:value="formValue.address" type="textarea" placeholder="请输入联系地址" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="登录验证码" path="loginCode">
|
||||
<n-radio-group v-model:value="formValue.loginCode" name="loginCode">
|
||||
<n-space>
|
||||
<n-radio :value="1">开启</n-radio>
|
||||
<n-radio :value="0">关闭</n-radio>
|
||||
</n-space>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="网站开启访问" path="systemOpen">
|
||||
<n-switch
|
||||
size="large"
|
||||
v-model:value="formValue.systemOpen"
|
||||
@update:value="systemOpenChange"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="网站关闭提示" path="closeText">
|
||||
<n-input
|
||||
v-model:value="formValue.closeText"
|
||||
type="textarea"
|
||||
placeholder="请输入网站关闭提示"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">更新基本信息</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { useDialog, useMessage } from 'naive-ui';
|
||||
|
||||
const rules = {
|
||||
name: {
|
||||
required: true,
|
||||
message: '请输入网站名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
mobile: {
|
||||
required: true,
|
||||
message: '请输入联系电话',
|
||||
trigger: 'input',
|
||||
},
|
||||
};
|
||||
|
||||
const formRef = ref();
|
||||
const message = useMessage();
|
||||
const dialog = useDialog();
|
||||
|
||||
const formValue = ref({
|
||||
name: '',
|
||||
mobile: '',
|
||||
icpCode: '',
|
||||
address: '',
|
||||
loginCode: 0,
|
||||
closeText:
|
||||
'网站维护中,暂时无法访问!本网站正在进行系统维护和技术升级,网站暂时无法访问,敬请谅解!',
|
||||
systemOpen: true,
|
||||
});
|
||||
|
||||
function systemOpenChange(value) {
|
||||
if (!value) {
|
||||
dialog.warning({
|
||||
title: '提示',
|
||||
content: '您确定要关闭系统访问吗?该操作立马生效,请慎重操作!',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
message.success('操作成功');
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
formValue.value.systemOpen = true;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function formSubmit() {
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
message.success('验证成功');
|
||||
} else {
|
||||
message.error('验证失败,请填写完整信息');
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@ -1,67 +0,0 @@
|
||||
<template>
|
||||
<n-grid cols="1 s:1 m:1 l:4 xl:4 2xl:4" responsive="screen">
|
||||
<n-grid-item>
|
||||
<n-form :label-width="120" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="发件人邮箱" path="originator">
|
||||
<n-input v-model:value="formValue.originator" placeholder="请输入发件人邮箱" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="SMTP服务器地址">
|
||||
<n-input placeholder="请输入SMTP服务器地址" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="SMTP服务器端口">
|
||||
<n-input placeholder="请输入SMTP服务器端口" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="SMTP用户名">
|
||||
<n-input placeholder="请输入SMTP用户名" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="SMTP密码">
|
||||
<n-input type="password" placeholder="请输入SMTP密码" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="邮件测试">
|
||||
<n-button>邮件测试</n-button>
|
||||
</n-form-item>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">更新邮件信息</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { useMessage } from 'naive-ui';
|
||||
|
||||
const rules = {
|
||||
originator: {
|
||||
required: true,
|
||||
message: '请输入发件人邮箱',
|
||||
trigger: 'blur',
|
||||
},
|
||||
};
|
||||
|
||||
const formRef = ref();
|
||||
const message = useMessage();
|
||||
|
||||
const formValue = ref({
|
||||
originator: '',
|
||||
});
|
||||
|
||||
function formSubmit() {
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
message.success('验证成功');
|
||||
} else {
|
||||
message.error('验证失败,请填写完整信息');
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@ -1,180 +0,0 @@
|
||||
<template>
|
||||
<n-grid cols="1 s:1 m:1 l:4 xl:4 2xl:4" responsive="screen">
|
||||
<n-grid-item>
|
||||
<n-form :label-width="120" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="商品图片(大)">
|
||||
<n-space align="center">
|
||||
<span>宽度:</span>
|
||||
<n-input
|
||||
v-model:value="formValue.bigWidth"
|
||||
style="width: 80px"
|
||||
placeholder="宽度像素"
|
||||
/>
|
||||
<span>高度:</span>
|
||||
<n-input
|
||||
v-model:value="formValue.bigHeight"
|
||||
style="width: 80px"
|
||||
placeholder="高度像素"
|
||||
/>
|
||||
</n-space>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="商品图片(小)">
|
||||
<n-space align="center">
|
||||
<span>宽度:</span>
|
||||
<n-input
|
||||
v-model:value="formValue.smallWidth"
|
||||
style="width: 80px"
|
||||
placeholder="宽度像素"
|
||||
/>
|
||||
<span>高度:</span>
|
||||
<n-input
|
||||
v-model:value="formValue.smallHeight"
|
||||
style="width: 80px"
|
||||
placeholder="高度像素"
|
||||
/>
|
||||
</n-space>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="水印透明度" path="watermarkClarity">
|
||||
<n-input-number
|
||||
v-model:value="formValue.watermarkClarity"
|
||||
:show-button="false"
|
||||
placeholder="请输入水印透明度"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="水印图片" path="watermarkClarity">
|
||||
<n-upload action="http://www.mocky.io/v2/5e4bafc63100007100d8b70f">
|
||||
<n-button>上传文件</n-button>
|
||||
</n-upload>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="水印位置" path="watermarkPlace">
|
||||
<n-select
|
||||
placeholder="请选择价格精确方式"
|
||||
:options="watermarkPlaceList"
|
||||
v-model:value="formValue.watermarkPlace"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="价格精确位数" path="pricePreciseNum">
|
||||
<n-select
|
||||
placeholder="请选择价格精确位数"
|
||||
:options="pricePreciseNumList"
|
||||
v-model:value="formValue.pricePreciseNum"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="价格精确方式" path="pricePrecise">
|
||||
<n-select
|
||||
placeholder="请选择价格精确方式"
|
||||
:options="pricePreciseList"
|
||||
v-model:value="formValue.pricePrecise"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="前台显示市场价" path="isMarketPrice">
|
||||
<n-switch size="large" v-model:value="formValue.isMarketPrice" />
|
||||
</n-form-item>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">更新显示信息</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import { FormRules, useMessage } from 'naive-ui';
|
||||
|
||||
const rules: FormRules = {
|
||||
name: {
|
||||
required: true,
|
||||
message: '请输入网站名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
mobile: {
|
||||
required: true,
|
||||
message: '请输入联系电话',
|
||||
trigger: 'input',
|
||||
},
|
||||
};
|
||||
const watermarkPlaceList = [
|
||||
{
|
||||
label: '左上',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: '右上',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: '居中',
|
||||
value: 3,
|
||||
},
|
||||
{
|
||||
label: '右下',
|
||||
value: 4,
|
||||
},
|
||||
];
|
||||
|
||||
const pricePreciseNumList = [
|
||||
{
|
||||
label: '2位',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: '3位',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: '4位',
|
||||
value: 3,
|
||||
},
|
||||
];
|
||||
const pricePreciseList = [
|
||||
{
|
||||
label: '四舍五入',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: '向上取整',
|
||||
value: 2,
|
||||
},
|
||||
{
|
||||
label: '向下取整',
|
||||
value: 3,
|
||||
},
|
||||
];
|
||||
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
|
||||
const formValue = reactive({
|
||||
bigWidth: '',
|
||||
bigHeight: '',
|
||||
smallWidth: '',
|
||||
smallHeight: '',
|
||||
watermarkClarity: null,
|
||||
pricePrecise: 1,
|
||||
isMarketPrice: true,
|
||||
pricePreciseNum: null,
|
||||
systemOpen: false,
|
||||
watermarkPlace: null,
|
||||
});
|
||||
|
||||
function formSubmit() {
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
message.success('验证成功');
|
||||
} else {
|
||||
message.error('验证失败,请填写完整信息');
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@ -1,43 +0,0 @@
|
||||
<template>
|
||||
<PageWrapper>
|
||||
<n-card :bordered="false" size="small" class="proCard tabsCard">
|
||||
<n-tabs type="line" size="large">
|
||||
<n-tab-pane name="basic" tab="基本设置">
|
||||
<BasicSetting />
|
||||
</n-tab-pane>
|
||||
<n-tab-pane name="reveal" tab="显示设置"><RevealSetting /></n-tab-pane>
|
||||
<n-tab-pane name="email" tab="邮件设置"><EmailSetting /></n-tab-pane>
|
||||
</n-tabs>
|
||||
</n-card>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { PageWrapper } from '@/components/Page';
|
||||
import BasicSetting from './BasicSetting.vue';
|
||||
import RevealSetting from './RevealSetting.vue';
|
||||
import EmailSetting from './EmailSetting.vue';
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.thing-cell {
|
||||
margin: 0 -16px 10px;
|
||||
padding: 5px 16px;
|
||||
|
||||
&:hover {
|
||||
background: #f3f3f3;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.thing-cell-on {
|
||||
background: #f0faff;
|
||||
color: #2d8cf0;
|
||||
|
||||
:deep(.n-thing-main .n-thing-header .n-thing-header__title) {
|
||||
color: #2d8cf0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: #f0faff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue
Block a user