feat: 项目初始化,未病局
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
<!--
|
||||
* @Description:连接配置
|
||||
* @Author: huguodong
|
||||
* @Date: 2024-11-07 13:55:56
|
||||
!-->
|
||||
<template>
|
||||
<el-form ref="baseFormRef" :rules="rules" :model="baseFormProps" label-width="auto" label-suffix=" :" label-position="top">
|
||||
<s-form-item label="MQTT服务端地址" prop="MQTT_PARAM_URL">
|
||||
<s-input v-model="baseFormProps.MQTT_PARAM_URL"></s-input>
|
||||
</s-form-item>
|
||||
<s-form-item label="MQTT用户名" prop="MQTT_PARAM_USERNAME">
|
||||
<s-input v-model="baseFormProps.MQTT_PARAM_USERNAME"></s-input>
|
||||
</s-form-item>
|
||||
<s-form-item label="MQTT密码" prop="MQTT_PARAM_PASSWORD">
|
||||
<s-input v-model="baseFormProps.MQTT_PARAM_PASSWORD"></s-input>
|
||||
</s-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="submitLoading" @click="onSubmit()">保存</el-button>
|
||||
<el-button style="margin-left: 10px" @click="resetForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SysConfig, sysConfigApi } from "@/api";
|
||||
import { FormInstance } from "element-plus";
|
||||
const submitLoading = ref(false); //提交按钮loading
|
||||
const baseFormRef = ref<FormInstance>();
|
||||
import { SysConfigTypeEnum } from "@/enums";
|
||||
|
||||
/**
|
||||
* @description: 连接配置参数
|
||||
*/
|
||||
const baseFormProps = reactive<SysConfig.MqttPolicyConfig>({
|
||||
MQTT_PARAM_URL: "",
|
||||
MQTT_PARAM_USERNAME: "",
|
||||
MQTT_PARAM_PASSWORD: ""
|
||||
});
|
||||
|
||||
//props定义
|
||||
const props = defineProps({
|
||||
baseConfig: {
|
||||
type: Array as PropType<SysConfig.ConfigInfo[]>,
|
||||
required: true,
|
||||
default: () => []
|
||||
}
|
||||
});
|
||||
|
||||
//监听loginPolicy变化
|
||||
watch(
|
||||
() => props.baseConfig,
|
||||
(newVal: SysConfig.ConfigInfo[]) => {
|
||||
//重新赋值
|
||||
newVal.forEach((item: SysConfig.ConfigInfo) => {
|
||||
(baseFormProps[item.configKey as keyof SysConfig.MqttPolicyConfig] as string) = item.configValue;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// 表单验证规则
|
||||
const rules = reactive({
|
||||
MQTT_PARAM_URL: [{ required: true, message: "请输入MQTT服务端地址", trigger: "blur" }],
|
||||
MQTT_PARAM_USERNAME: [{ required: true, message: "请输入MQTT用户名", trigger: "blur" }],
|
||||
MQTT_PARAM_PASSWORD: [{ required: true, message: "请输入MQTT密码", trigger: "blur" }]
|
||||
});
|
||||
|
||||
/** 提交表单 */
|
||||
function onSubmit() {
|
||||
baseFormRef.value?.validate(async valid => {
|
||||
if (!valid) return; //表单验证失败
|
||||
submitLoading.value = true;
|
||||
//组装参数
|
||||
const param: SysConfig.ConfigInfo[] = Object.entries(baseFormProps).map(item => {
|
||||
return {
|
||||
id: 0,
|
||||
category: SysConfigTypeEnum.MQTT_POLICY,
|
||||
configKey: item[0],
|
||||
configValue: typeof item[1] === "object" ? JSON.stringify(item[1]) : String(item[1])
|
||||
};
|
||||
});
|
||||
//提交数据
|
||||
sysConfigApi.configEditForm(param).finally(() => {
|
||||
submitLoading.value = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
/** 重置表单 */
|
||||
function resetForm() {
|
||||
baseFormRef.value?.resetFields();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -0,0 +1,46 @@
|
||||
<!--
|
||||
* @Description: 安全配置
|
||||
* @Author: huguodong
|
||||
* @Date: 2024-01-31 15:33:50
|
||||
!-->
|
||||
<template>
|
||||
<el-tabs v-model="activeName" class="demo-tabs" tab-position="left">
|
||||
<el-tab-pane label="连接配置" name="base" class="pl-5"><BaseForm :base-config="baseConfig" /></el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SysConfig } from "@/api";
|
||||
import BaseForm from "./baseForm.vue";
|
||||
import { SysConfigTypeEnum } from "@/enums";
|
||||
|
||||
const activeName = ref("base");
|
||||
const baseConfig = ref<SysConfig.ConfigInfo[]>([]);
|
||||
|
||||
//props定义
|
||||
const props = defineProps({
|
||||
sysConfigs: {
|
||||
type: Array as PropType<SysConfig.ConfigInfo[]>,
|
||||
required: true,
|
||||
default: () => []
|
||||
}
|
||||
});
|
||||
|
||||
//监听sysConfigs变化
|
||||
watch(
|
||||
() => props.sysConfigs,
|
||||
(newVal: SysConfig.ConfigInfo[]) => {
|
||||
// 配置赋值
|
||||
baseConfig.value = newVal.filter(item => item.category == SysConfigTypeEnum.MQTT_POLICY);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.demo-tabs > .el-tabs__content {
|
||||
padding: 32px;
|
||||
font-size: 132px;
|
||||
font-weight: 600;
|
||||
color: #6b778c;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,104 @@
|
||||
<!--
|
||||
* @Description: 配置表单
|
||||
* @Author: huguodong
|
||||
* @Date: 2024-02-02 10:49:28
|
||||
!-->
|
||||
<template>
|
||||
<form-container v-model="visible" :title="`${configProps.opt}配置`" form-size="600px">
|
||||
<el-form
|
||||
ref="configFormRef"
|
||||
:rules="rules"
|
||||
:disabled="configProps.disabled"
|
||||
:model="configProps.record"
|
||||
:hide-required-asterisk="configProps.disabled"
|
||||
label-width="auto"
|
||||
label-suffix=" :"
|
||||
>
|
||||
<s-form-item label="配置键" prop="configKey">
|
||||
<s-input v-model="configProps.record.configKey"></s-input>
|
||||
</s-form-item>
|
||||
<s-form-item label="配置值" prop="configValue">
|
||||
<s-input v-model="configProps.record.configValue"></s-input>
|
||||
</s-form-item>
|
||||
<s-form-item label="备注" prop="remark">
|
||||
<s-input v-model="configProps.record.remark"></s-input>
|
||||
</s-form-item>
|
||||
<s-form-item label="排序" prop="sortCode">
|
||||
<el-slider v-model="configProps.record.sortCode" show-input :min="1" />
|
||||
</s-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="onClose"> 取消 </el-button>
|
||||
<el-button v-show="!configProps.disabled" type="primary" @click="handleSubmit"> 确定 </el-button>
|
||||
</template>
|
||||
</form-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SysConfig, sysConfigApi } from "@/api";
|
||||
import { required } from "@/utils/formRules";
|
||||
import { FormOptEnum } from "@/enums";
|
||||
import { FormInstance } from "element-plus";
|
||||
|
||||
const visible = ref(false); //是否显示表单
|
||||
|
||||
// 表单参数接口
|
||||
interface ConfigProps extends FormProps.Base<SysConfig.ConfigInfo> {}
|
||||
|
||||
// 表单参数
|
||||
const configProps = reactive<ConfigProps>({
|
||||
opt: FormOptEnum.ADD,
|
||||
record: {},
|
||||
disabled: false
|
||||
});
|
||||
|
||||
// 表单验证规则
|
||||
const rules = reactive({
|
||||
configKey: [required("请输入配置键")],
|
||||
configValue: [required("请输入配置值")],
|
||||
sortCode: [required("请输入排序")]
|
||||
});
|
||||
|
||||
/**
|
||||
* 打开表单
|
||||
* @param props 表单参数
|
||||
*/
|
||||
function onOpen(props: ConfigProps) {
|
||||
Object.assign(configProps, props); //合并参数
|
||||
if (props.opt == FormOptEnum.ADD) {
|
||||
//如果是新增,设置默认值
|
||||
configProps.record.sortCode = 99;
|
||||
}
|
||||
visible.value = true; //显示表单
|
||||
}
|
||||
|
||||
// 提交数据(新增/编辑)
|
||||
const configFormRef = ref<FormInstance>();
|
||||
/** 提交表单 */
|
||||
async function handleSubmit() {
|
||||
configFormRef.value?.validate(async valid => {
|
||||
if (!valid) return; //表单验证失败
|
||||
//提交表单
|
||||
await sysConfigApi
|
||||
.submitForm(configProps.record, configProps.record.id != undefined)
|
||||
.then(() => {
|
||||
configProps.successful!(); //调用父组件的successful方法
|
||||
})
|
||||
.finally(() => {
|
||||
onClose();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 关闭表单*/
|
||||
function onClose() {
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
// 暴露给父组件的方法
|
||||
defineExpose({
|
||||
onOpen
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -0,0 +1,80 @@
|
||||
<!--
|
||||
* @Description: 其他配置
|
||||
* @Author: huguodong
|
||||
* @Date: 2024-02-02 08:43:44
|
||||
!-->
|
||||
<template>
|
||||
<div class="table-box min-h-300px">
|
||||
<ProTable ref="proTable" class="table" :columns="columns" :request-api="sysConfigApi.page">
|
||||
<!-- 表格 header 按钮 -->
|
||||
<template #tableHeader>
|
||||
<s-button :suffix="title" @click="onOpen(FormOptEnum.ADD)" />
|
||||
</template>
|
||||
<!-- 操作 -->
|
||||
<template #operation="scope">
|
||||
<s-button link :opt="FormOptEnum.EDIT" @click="onOpen(FormOptEnum.EDIT, scope.row)" />
|
||||
<s-button link :opt="FormOptEnum.DELETE" @click="onDelete(scope.row.id, `删除【${scope.row.configKey}】配置`)" />
|
||||
</template>
|
||||
</ProTable>
|
||||
<!-- 新增/编辑表单 -->
|
||||
<Form ref="formRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { sysConfigApi, SysConfig } from "@/api";
|
||||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
|
||||
import { useHandleData } from "@/hooks/useHandleData";
|
||||
import { FormOptEnum } from "@/enums";
|
||||
import Form from "./form.vue";
|
||||
|
||||
const title = "配置";
|
||||
|
||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
|
||||
const proTable = ref<ProTableInstance>();
|
||||
|
||||
// 表格配置项
|
||||
const columns: ColumnProps<SysConfig.ConfigInfo>[] = [
|
||||
{ type: "selection", fixed: "left", width: 50 },
|
||||
{ prop: "configKey", label: "配置键" },
|
||||
{ prop: "configValue", label: "配置值" },
|
||||
{ prop: "remark", label: "备注" },
|
||||
{ prop: "sortCode", label: "排序", width: 80 },
|
||||
{ prop: "operation", label: "操作", fixed: "right", width: 150 }
|
||||
];
|
||||
|
||||
// 表单引用
|
||||
const formRef = ref<InstanceType<typeof Form> | null>(null);
|
||||
|
||||
/**
|
||||
* 打开表单
|
||||
* @param opt 操作类型
|
||||
* @param record 记录
|
||||
*/
|
||||
function onOpen(opt: FormOptEnum, record: {} | SysConfig.ConfigInfo = {}) {
|
||||
formRef.value?.onOpen({
|
||||
opt: opt,
|
||||
record: record,
|
||||
successful: RefreshTable //刷新子表格
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param ids id数组
|
||||
*/
|
||||
async function onDelete(id: number | string, msg: string) {
|
||||
// 二次确认 => 请求api => 刷新表格
|
||||
await useHandleData(sysConfigApi.delete, { id }, msg);
|
||||
RefreshTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新表格
|
||||
*/
|
||||
function RefreshTable() {
|
||||
proTable.value?.refresh(); //刷新主表格
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -0,0 +1,53 @@
|
||||
<!--
|
||||
* @Description: 安全配置
|
||||
* @Author: huguodong
|
||||
* @Date: 2024-01-31 15:33:50
|
||||
!-->
|
||||
<template>
|
||||
<el-tabs v-model="activeName" class="demo-tabs" tab-position="left">
|
||||
<el-tab-pane label="登录策略" name="login" class="pl-5"><LoginForm :login-policy="loginPolicy" /></el-tab-pane>
|
||||
<el-tab-pane label="密码策略" name="pwd" class="pl-5"><PwdForm :pwd-policy="pwdPolicy" /></el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SysConfig } from "@/api";
|
||||
import LoginForm from "./loginForm.vue";
|
||||
import PwdForm from "./pwdForm.vue";
|
||||
import { SysConfigTypeEnum } from "@/enums";
|
||||
|
||||
const activeName = ref("login");
|
||||
const loginPolicy = ref<SysConfig.ConfigInfo[]>([]);
|
||||
const pwdPolicy = ref<SysConfig.ConfigInfo[]>([]);
|
||||
|
||||
//props定义
|
||||
const props = defineProps({
|
||||
sysConfigs: {
|
||||
type: Array as PropType<SysConfig.ConfigInfo[]>,
|
||||
required: true,
|
||||
default: () => []
|
||||
}
|
||||
});
|
||||
|
||||
//监听sysConfigs变化
|
||||
watch(
|
||||
() => props.sysConfigs,
|
||||
(newVal: SysConfig.ConfigInfo[]) => {
|
||||
// 配置赋值
|
||||
loginPolicy.value = newVal.filter(item => item.category == SysConfigTypeEnum.LOGIN_POLICY);
|
||||
pwdPolicy.value = newVal.filter(item => item.category == SysConfigTypeEnum.PWD_POLICY);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.demo-tabs > .el-tabs__content {
|
||||
padding: 32px;
|
||||
font-size: 132px;
|
||||
font-weight: 600;
|
||||
color: #6b778c;
|
||||
}
|
||||
:deep(.el-tabs__nav-scroll) {
|
||||
height: 500px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,119 @@
|
||||
<!--
|
||||
* @Description: 登录策略
|
||||
* @Author: huguodong
|
||||
* @Date: 2024-01-31 16:25:48
|
||||
!-->
|
||||
<template>
|
||||
<el-form ref="loginFormRef" :rules="rules" :model="loginFormProps" label-width="auto" label-suffix=" :" label-position="top">
|
||||
<s-form-item label="单用户登录开关" prop="LOGIN_SINGLE_OPEN">
|
||||
<s-radio-group v-model="loginFormProps.LOGIN_SINGLE_OPEN" :options="yesNoOptions" />
|
||||
</s-form-item>
|
||||
<s-form-item label="允许登录错误次数" prop="LOGIN_ERROR_COUNT">
|
||||
<el-input-number v-model.number="loginFormProps.LOGIN_ERROR_COUNT" :min="1" :max="999" />
|
||||
</s-form-item>
|
||||
<s-form-item label="登录错误重置时间(分)" prop="LOGIN_ERROR_RESET_TIME">
|
||||
<el-input-number v-model.number="loginFormProps.LOGIN_ERROR_RESET_TIME" :min="1" :max="999" />
|
||||
</s-form-item>
|
||||
<s-form-item label="登录错误次数过多账号锁定时长:(分)" prop="LOGIN_ERROR_LOCK">
|
||||
<el-input-number v-model.number="loginFormProps.LOGIN_ERROR_LOCK" :min="1" :max="999" />
|
||||
</s-form-item>
|
||||
<s-form-item label="登录验证码开关" prop="LOGIN_CAPTCHA_OPEN">
|
||||
<s-radio-group v-model="loginFormProps.LOGIN_CAPTCHA_OPEN" :options="yesNoOptions" />
|
||||
</s-form-item>
|
||||
<s-form-item label="登录验证码类型" prop="LOGIN_CAPTCHA_TYPE">
|
||||
<s-radio-group v-model="loginFormProps.LOGIN_CAPTCHA_TYPE" :options="captchaOptions" />
|
||||
</s-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="submitLoading" @click="onSubmit()">保存</el-button>
|
||||
<el-button style="margin-left: 10px" @click="resetForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SysConfig, sysConfigApi } from "@/api";
|
||||
import { FormInstance } from "element-plus";
|
||||
import { useDictStore } from "@/stores/modules";
|
||||
import { SysConfigTypeEnum, SysDictEnum } from "@/enums";
|
||||
|
||||
const dictStore = useDictStore(); //字典仓库
|
||||
|
||||
// 字典类型选项
|
||||
const yesNoOptions = dictStore.getDictList(SysDictEnum.YES_NO);
|
||||
const captchaOptions = dictStore.getDictList(SysDictEnum.CAPTCHA_TYPE);
|
||||
const submitLoading = ref(false); //提交按钮loading
|
||||
const loginFormRef = ref<FormInstance>();
|
||||
|
||||
/** 登录策略参数 */
|
||||
const loginFormProps = reactive<SysConfig.LoginPolicyConfig>({
|
||||
LOGIN_SINGLE_OPEN: yesNoOptions[0].value,
|
||||
LOGIN_CAPTCHA_OPEN: yesNoOptions[0].value,
|
||||
LOGIN_CAPTCHA_TYPE: captchaOptions[0].value,
|
||||
LOGIN_ERROR_COUNT: 5,
|
||||
LOGIN_ERROR_RESET_TIME: 5,
|
||||
LOGIN_ERROR_LOCK: 30
|
||||
});
|
||||
|
||||
//props定义
|
||||
const props = defineProps({
|
||||
loginPolicy: {
|
||||
type: Array as PropType<SysConfig.ConfigInfo[]>,
|
||||
required: true,
|
||||
default: () => []
|
||||
}
|
||||
});
|
||||
|
||||
//监听loginPolicy变化
|
||||
watch(
|
||||
() => props.loginPolicy,
|
||||
(newVal: SysConfig.ConfigInfo[]) => {
|
||||
//重新赋值
|
||||
newVal.forEach((item: SysConfig.ConfigInfo) => {
|
||||
let prop = loginFormProps[item.configKey as keyof SysConfig.LoginPolicyConfig];
|
||||
//如果是number类型就转为number
|
||||
if (typeof prop === "number") {
|
||||
(loginFormProps[item.configKey as keyof SysConfig.LoginPolicyConfig] as number) = Number(item.configValue);
|
||||
} else {
|
||||
(loginFormProps[item.configKey as keyof SysConfig.LoginPolicyConfig] as string) = item.configValue;
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// 表单验证规则
|
||||
const rules = reactive({
|
||||
LOGIN_ERROR_COUNT: [{ required: true, message: "请输入允许登录错误次数", trigger: "blur" }],
|
||||
LOGIN_ERROR_RESET_TIME: [{ required: true, message: "请输入登录错误重置时间", trigger: "blur" }],
|
||||
LOGIN_ERROR_LOCK: [{ required: true, message: "请输入登录错误次数过多账号锁定时长", trigger: "blur" }],
|
||||
LOGIN_CAPTCHA_TYPE: [{ required: true, message: "请选择登录验证码类型", trigger: "blur" }],
|
||||
LOGIN_SINGLE_OPEN: [{ required: true, message: "请选择单用户登录开关", trigger: "blur" }],
|
||||
LOGIN_CAPTCHA_OPEN: [{ required: true, message: "请选择登录验证码开关", trigger: "blur" }]
|
||||
});
|
||||
|
||||
/** 提交表单 */
|
||||
function onSubmit() {
|
||||
loginFormRef.value?.validate(async valid => {
|
||||
if (!valid) return; //表单验证失败
|
||||
submitLoading.value = true;
|
||||
//组装参数
|
||||
const param: SysConfig.ConfigInfo[] = Object.entries(loginFormProps).map(item => {
|
||||
return {
|
||||
id: 0,
|
||||
category: SysConfigTypeEnum.LOGIN_POLICY,
|
||||
configKey: item[0],
|
||||
configValue: typeof item[1] === "object" ? JSON.stringify(item[1]) : String(item[1])
|
||||
};
|
||||
});
|
||||
//提交数据
|
||||
sysConfigApi.configEditForm(param).finally(() => {
|
||||
submitLoading.value = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
/** 重置表单 */
|
||||
function resetForm() {
|
||||
loginFormRef.value?.resetFields();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -0,0 +1,143 @@
|
||||
<!--
|
||||
* @Description: 密码策略
|
||||
* @Author: huguodong
|
||||
* @Date: 2024-01-31 16:25:33
|
||||
!-->
|
||||
<template>
|
||||
<el-form ref="pwdFormRef" :rules="rules" :model="pwdFormProps" label-width="auto" label-suffix=" :" label-position="top">
|
||||
<s-form-item label="系统默认密码" prop="PWD_DEFAULT_PASSWORD" class="w-50">
|
||||
<s-input v-model="pwdFormProps.PWD_DEFAULT_PASSWORD"></s-input>
|
||||
</s-form-item>
|
||||
<s-form-item label="密码定期提醒更新" prop="PWD_REMIND">
|
||||
<s-radio-group v-model="pwdFormProps.PWD_REMIND" :options="yesNoOptions" />
|
||||
</s-form-item>
|
||||
<s-form-item label="密码定期提醒更新时间(天)" prop="LOGIN_ERROR_LOCK">
|
||||
<el-input-number v-model.number="pwdFormProps.PWD_REMIND_DAY" :min="1" :max="999" />
|
||||
</s-form-item>
|
||||
<s-form-item label="修改初始密码提醒" prop="PWD_UPDATE_DEFAULT">
|
||||
<s-radio-group v-model="pwdFormProps.PWD_UPDATE_DEFAULT" :options="yesNoOptions" />
|
||||
</s-form-item>
|
||||
<s-form-item label="密码最小长度" prop="PWD_MIN_LENGTH">
|
||||
<el-input-number v-model.number="pwdFormProps.PWD_MIN_LENGTH" :min="6" :max="20" />
|
||||
</s-form-item>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="6">
|
||||
<s-form-item label="是否含数字" prop="PWD_CONTAIN_NUM">
|
||||
<s-radio-group v-model="pwdFormProps.PWD_CONTAIN_NUM" :options="yesNoOptions" />
|
||||
</s-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<s-form-item label="是否包含小写字母" prop="PWD_CONTAIN_LOWER">
|
||||
<s-radio-group v-model="pwdFormProps.PWD_CONTAIN_LOWER" :options="yesNoOptions" />
|
||||
</s-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<s-form-item label="是否包含大写字母" prop="PWD_CONTAIN_UPPER">
|
||||
<s-radio-group v-model="pwdFormProps.PWD_CONTAIN_UPPER" :options="yesNoOptions" />
|
||||
</s-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<s-form-item label="是否包含特殊字符" prop="PWD_CONTAIN_CHARACTER">
|
||||
<s-radio-group v-model="pwdFormProps.PWD_CONTAIN_CHARACTER" :options="yesNoOptions" />
|
||||
</s-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="submitLoading" @click="onSubmit()">保存</el-button>
|
||||
<el-button style="margin-left: 10px" @click="resetForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SysConfig, sysConfigApi } from "@/api";
|
||||
import { FormInstance } from "element-plus";
|
||||
import { useDictStore } from "@/stores/modules";
|
||||
import { SysConfigTypeEnum, SysDictEnum } from "@/enums";
|
||||
|
||||
const dictStore = useDictStore(); //字典仓库
|
||||
|
||||
// 字典类型选项
|
||||
const yesNoOptions = dictStore.getDictList(SysDictEnum.YES_NO);
|
||||
const submitLoading = ref(false); //提交按钮loading
|
||||
const pwdFormRef = ref<FormInstance>();
|
||||
|
||||
/** 登录策略参数 */
|
||||
const pwdFormProps = reactive<SysConfig.PwdPolicyConfig>({
|
||||
PWD_DEFAULT_PASSWORD: "",
|
||||
PWD_REMIND: yesNoOptions[0].value,
|
||||
PWD_REMIND_DAY: 30,
|
||||
PWD_UPDATE_DEFAULT: yesNoOptions[0].value,
|
||||
PWD_MIN_LENGTH: 6,
|
||||
PWD_CONTAIN_NUM: yesNoOptions[0].value,
|
||||
PWD_CONTAIN_LOWER: yesNoOptions[0].value,
|
||||
PWD_CONTAIN_UPPER: yesNoOptions[0].value,
|
||||
PWD_CONTAIN_CHARACTER: yesNoOptions[0].value
|
||||
});
|
||||
|
||||
//props定义
|
||||
const props = defineProps({
|
||||
pwdPolicy: {
|
||||
type: Array as PropType<SysConfig.ConfigInfo[]>,
|
||||
required: true,
|
||||
default: () => []
|
||||
}
|
||||
});
|
||||
|
||||
//监听pwdPolicy变化
|
||||
watch(
|
||||
() => props.pwdPolicy,
|
||||
(newVal: SysConfig.ConfigInfo[]) => {
|
||||
//重新赋值
|
||||
newVal.forEach((item: SysConfig.ConfigInfo) => {
|
||||
let prop = pwdFormProps[item.configKey as keyof SysConfig.PwdPolicyConfig];
|
||||
//如果是number类型就转为number
|
||||
if (typeof prop === "number") {
|
||||
(pwdFormProps[item.configKey as keyof SysConfig.PwdPolicyConfig] as number) = Number(item.configValue);
|
||||
} else {
|
||||
(pwdFormProps[item.configKey as keyof SysConfig.PwdPolicyConfig] as string) = item.configValue;
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// 表单验证规则
|
||||
const rules = reactive({
|
||||
PWD_DEFAULT_PASSWORD: [{ required: true, message: "请输入系统默认密码", trigger: "blur" }],
|
||||
PWD_REMIND: [{ required: true, message: "请选择密码定期提醒更新", trigger: "blur" }],
|
||||
PWD_REMIND_DAY: [{ required: true, message: "请输入密码定期提醒更新时间", trigger: "blur" }],
|
||||
PWD_UPDATE_DEFAULT: [{ required: true, message: "请选择修改初始密码提醒", trigger: "blur" }],
|
||||
PWD_MIN_LENGTH: [{ required: true, message: "请输入密码最小长度", trigger: "blur" }],
|
||||
PWD_CONTAIN_NUM: [{ required: true, message: "请选择是否含数字", trigger: "blur" }],
|
||||
PWD_CONTAIN_LOWER: [{ required: true, message: "请选择是否包含小写字母", trigger: "blur" }],
|
||||
PWD_CONTAIN_UPPER: [{ required: true, message: "请选择是否包含大写字母", trigger: "blur" }],
|
||||
PWD_CONTAIN_CHARACTER: [{ required: true, message: "请选择是否包含特殊字符", trigger: "blur" }]
|
||||
});
|
||||
|
||||
/** 提交表单 */
|
||||
function onSubmit() {
|
||||
pwdFormRef.value?.validate(async valid => {
|
||||
if (!valid) return; //表单验证失败
|
||||
submitLoading.value = true;
|
||||
//组装参数
|
||||
const param: SysConfig.ConfigInfo[] = Object.entries(pwdFormProps).map(item => {
|
||||
return {
|
||||
id: 0,
|
||||
category: SysConfigTypeEnum.LOGIN_POLICY,
|
||||
configKey: item[0],
|
||||
configValue: typeof item[1] === "object" ? JSON.stringify(item[1]) : String(item[1])
|
||||
};
|
||||
});
|
||||
//提交数据
|
||||
sysConfigApi.configEditForm(param).finally(() => {
|
||||
submitLoading.value = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
/** 重置表单 */
|
||||
function resetForm() {
|
||||
pwdFormRef.value?.resetFields();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -0,0 +1,307 @@
|
||||
<!--
|
||||
* @Description: 系统配置
|
||||
* @Author: huguodong
|
||||
* @Date: 2024-01-22 16:44:07
|
||||
!-->
|
||||
<template>
|
||||
<div>
|
||||
<el-form ref="sysConfigFormRef" :rules="rules" :model="sysBaseProps" label-width="auto" label-suffix=" :" label-position="top">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<s-form-item label="系统LOGO" prop="SYS_LOGO">
|
||||
<UploadImg v-model:image-url="sysBaseProps.SYS_LOGO" width="135px" height="135px" :file-size="3" :auto-upload="false">
|
||||
<template #empty>
|
||||
<el-icon><Avatar /></el-icon>
|
||||
<span>请上传LOGO</span>
|
||||
</template>
|
||||
</UploadImg>
|
||||
</s-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<s-form-item label="系统ico文件" prop="SYS_ICO">
|
||||
<UploadImg
|
||||
v-model:image-url="sysBaseProps.SYS_ICO!"
|
||||
width="135px"
|
||||
height="135px"
|
||||
:file-size="1"
|
||||
:file-type="icoType"
|
||||
:auto-upload="false"
|
||||
>
|
||||
<template #empty>
|
||||
<el-icon><Picture /></el-icon>
|
||||
<span>请上传.ICO文件</span>
|
||||
</template>
|
||||
</UploadImg>
|
||||
</s-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<s-form-item label="系统名称" prop="SYS_NAME">
|
||||
<s-input v-model="sysBaseProps.SYS_NAME"></s-input>
|
||||
</s-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<s-form-item label="系统版本" prop="SYS_VERSION">
|
||||
<s-input v-model="sysBaseProps.SYS_VERSION"></s-input>
|
||||
</s-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<s-form-item label="默认快捷方式" prop="SYS_DEFAULT_WORKBENCH_DATA">
|
||||
<MenuSelector
|
||||
v-model:menu-value="sysBaseProps.SYS_DEFAULT_WORKBENCH_DATA!.shortcut"
|
||||
multiple
|
||||
:check-strictly="false"
|
||||
:menu-tree-api="menuApi.menuTreeSelector"
|
||||
/>
|
||||
</s-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<s-form-item label="多租户配置" prop="SYS_TENANT_OPTIONS">
|
||||
<s-radio-group v-model="sysBaseProps.SYS_TENANT_OPTIONS" :options="tenantOptions" button />
|
||||
</s-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<s-form-item label="版权信息" prop="SYS_COPYRIGHT">
|
||||
<s-input v-model="sysBaseProps.SYS_COPYRIGHT"></s-input>
|
||||
</s-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<s-form-item label="版权链接URL" prop="SYS_COPYRIGHT_URL">
|
||||
<s-input v-model="sysBaseProps.SYS_COPYRIGHT_URL"></s-input>
|
||||
</s-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<s-form-item label="底部超链接" prop="SYS_FOOTER_LINKS">
|
||||
<el-tag
|
||||
v-for="tag in sysBaseProps.SYS_FOOTER_LINKS"
|
||||
:key="tag.name"
|
||||
class="mx-1"
|
||||
closable
|
||||
:disable-transitions="false"
|
||||
@close="handleClose(tag.name)"
|
||||
@click="linkDetail(tag)"
|
||||
>
|
||||
{{ tag.name }}
|
||||
</el-tag>
|
||||
|
||||
<el-button class="ml-1" size="small" @click="showLinkModel()">添加</el-button>
|
||||
</s-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<s-form-item label="网站开启访问(仅业务)" prop="SYS_WEB_STATUS">
|
||||
<s-radio-group v-model="sysBaseProps.SYS_WEB_STATUS" :options="statusOptions" button />
|
||||
</s-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<s-form-item label="网站关闭提示" prop="SYS_WEB_CLOSE_PROMPT">
|
||||
<s-input v-model="sysBaseProps.SYS_WEB_CLOSE_PROMPT" :rows="3" type="textarea"></s-input>
|
||||
</s-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="24">
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="submitLoading" @click="onSubmit()">保存</el-button>
|
||||
<el-button style="margin-left: 10px" @click="resetForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<!-- 超链接弹窗 -->
|
||||
<el-dialog v-model="dialogVisible" title="超链接信息" width="30%" show-close destroy-on-close>
|
||||
<el-form ref="linkFormRef" :model="linkForm" :rules="linkRules" label-width="auto" label-suffix=" :" label-position="top">
|
||||
<s-form-item label="超链接名称" prop="name">
|
||||
<s-input v-model="linkForm.name"></s-input>
|
||||
</s-form-item>
|
||||
<s-form-item label="超链接地址" prop="url">
|
||||
<s-input v-model="linkForm.url"></s-input>
|
||||
</s-form-item>
|
||||
<s-form-item label="排序" prop="sortCode">
|
||||
<el-slider v-model="linkForm.sortCode" show-input :min="1" />
|
||||
</s-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="saveLink">确定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SysConfig, menuApi, sysConfigApi } from "@/api";
|
||||
import { required } from "@/utils/formRules";
|
||||
import { useDictStore } from "@/stores/modules";
|
||||
import { SysDictEnum, SysConfigTypeEnum, SysBaseEnum, TenantEnum } from "@/enums";
|
||||
import { FormInstance } from "element-plus";
|
||||
|
||||
const dictStore = useDictStore(); //字典仓库
|
||||
// 字典类型选项
|
||||
const statusOptions = dictStore.getDictList(SysDictEnum.COMMON_STATUS);
|
||||
//多租户选项
|
||||
const tenantOptions = dictStore.getDictList(SysDictEnum.TENANT_OPTIONS);
|
||||
|
||||
const icoType: File.ImageMimeType[] = ["image/x-icon"]; //ico文件类型
|
||||
const submitLoading = ref(false); //提交按钮loading
|
||||
const sysConfigFormRef = ref<FormInstance>(); //表单实例
|
||||
/** 系统配置 */
|
||||
const sysBaseProps = reactive<SysConfig.SysBaseConfig>({
|
||||
SYS_NAME: "",
|
||||
SYS_LOGO: "",
|
||||
SYS_ICO: "",
|
||||
SYS_VERSION: "",
|
||||
SYS_COPYRIGHT: "",
|
||||
SYS_COPYRIGHT_URL: "",
|
||||
SYS_DEFAULT_WORKBENCH_DATA: { shortcut: [] },
|
||||
SYS_WEB_STATUS: statusOptions[0].value,
|
||||
SYS_WEB_CLOSE_PROMPT: "",
|
||||
SYS_TENANT_OPTIONS: TenantEnum.CLOSE,
|
||||
SYS_FOOTER_LINKS: []
|
||||
});
|
||||
|
||||
//定义props
|
||||
const props = defineProps({
|
||||
sysConfigs: {
|
||||
type: Array as PropType<SysConfig.ConfigInfo[]>,
|
||||
required: true,
|
||||
default: () => []
|
||||
}
|
||||
});
|
||||
|
||||
//监听sysConfigs变化
|
||||
watch(
|
||||
() => props.sysConfigs,
|
||||
(newVal: SysConfig.ConfigInfo[]) => {
|
||||
//重新赋值
|
||||
newVal.forEach((item: SysConfig.ConfigInfo) => {
|
||||
//如果是对象类型的属性就转成对象
|
||||
if (item.configKey == SysBaseEnum.SYS_DEFAULT_WORKBENCH_DATA) {
|
||||
const workBenchData: SysConfig.WorkBenchData = JSON.parse(item.configValue);
|
||||
sysBaseProps.SYS_DEFAULT_WORKBENCH_DATA = workBenchData;
|
||||
} else if (item.configKey == SysBaseEnum.SYS_FOOTER_LINKS) {
|
||||
const footerLinks: SysConfig.FooterLinkProps[] = JSON.parse(item.configValue);
|
||||
sysBaseProps.SYS_FOOTER_LINKS = footerLinks;
|
||||
} else {
|
||||
// 其他属性直接赋值
|
||||
(sysBaseProps[item.configKey as keyof SysConfig.SysBaseConfig] as string) = item.configValue;
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// 表单验证规则
|
||||
const rules = reactive({
|
||||
SYS_NAME: [required("请输入系统名称")],
|
||||
SYS_LOGO: [required("请上传系统LOGO")],
|
||||
SYS_ICO: [required("请上传系统ICO")],
|
||||
SYS_VERSION: [required("请输入系统版本")],
|
||||
SYS_COPYRIGHT: [required("请输入系统版权")],
|
||||
SYS_COPYRIGHT_URL: [required("请输入系统版权链接")],
|
||||
SYS_DEFAULT_WORKBENCH_DATA: [required("请输入系统默认工作台数据")],
|
||||
SYS_WEB_STATUS: [required("请选择网站开启访问状态")],
|
||||
SYS_WEB_CLOSE_PROMPT: [required("请输入网站关闭提示")]
|
||||
});
|
||||
|
||||
const dialogVisible = ref(false); // 是否显示弹窗
|
||||
// 超链接临时对象
|
||||
const linkTmp = ref<SysConfig.FooterLinkProps>({
|
||||
name: "",
|
||||
url: "",
|
||||
sortCode: 99
|
||||
});
|
||||
// 是否是添加超链接
|
||||
const linkFormRef = ref<FormInstance>(); // 超链接表单实例
|
||||
// 超链接表单参数
|
||||
const linkForm = reactive<SysConfig.FooterLinkProps>({
|
||||
name: "",
|
||||
url: "",
|
||||
sortCode: 99
|
||||
});
|
||||
|
||||
// 表单验证规则
|
||||
const linkRules = reactive({
|
||||
name: [required("请输入超链接名称")],
|
||||
url: [required("请输入超链接地址")],
|
||||
sortCode: [required("请输入排序")]
|
||||
});
|
||||
|
||||
/** 删除超链接 */
|
||||
function handleClose(tag: string) {
|
||||
sysBaseProps.SYS_FOOTER_LINKS = sysBaseProps.SYS_FOOTER_LINKS.filter(item => item.name != tag);
|
||||
}
|
||||
|
||||
/** 打开超链接详情 */
|
||||
function linkDetail(value: SysConfig.FooterLinkProps) {
|
||||
linkTmp.value = value;
|
||||
linkForm.name = value.name;
|
||||
linkForm.url = value.url;
|
||||
linkForm.sortCode = value.sortCode;
|
||||
dialogVisible.value = true;
|
||||
}
|
||||
|
||||
/** 显示超链接表单 */
|
||||
function showLinkModel() {
|
||||
dialogVisible.value = true;
|
||||
}
|
||||
|
||||
/** 保存超链接 */
|
||||
function saveLink() {
|
||||
linkFormRef.value?.validate(async valid => {
|
||||
if (!valid) return; //表单验证失败
|
||||
//判断是编辑还是添加
|
||||
if (linkTmp.value.name) {
|
||||
//删除旧的值,添加新的值
|
||||
sysBaseProps.SYS_FOOTER_LINKS = sysBaseProps.SYS_FOOTER_LINKS.filter(item => item.name != linkTmp.value.name);
|
||||
}
|
||||
sysBaseProps.SYS_FOOTER_LINKS.push({ ...linkForm });
|
||||
//根据sortCode排序,sortCode越小越靠前
|
||||
sysBaseProps.SYS_FOOTER_LINKS.sort((a, b) => a.sortCode - b.sortCode);
|
||||
//关闭弹窗,恢复默认值
|
||||
dialogVisible.value = false;
|
||||
linkTmp.value.name = "";
|
||||
linkTmp.value.url = "";
|
||||
linkTmp.value.sortCode = 99;
|
||||
linkFormRef.value?.resetFields();
|
||||
});
|
||||
}
|
||||
|
||||
/** 提交表单 */
|
||||
function onSubmit() {
|
||||
sysConfigFormRef.value?.validate(async valid => {
|
||||
if (!valid) return; //表单验证失败
|
||||
submitLoading.value = true;
|
||||
//组装参数
|
||||
const param: SysConfig.ConfigInfo[] = Object.entries(sysBaseProps).map(item => {
|
||||
return {
|
||||
id: 0,
|
||||
category: SysConfigTypeEnum.SYS_BASE,
|
||||
configKey: item[0],
|
||||
//configValue 如果是对象就转成json字符串
|
||||
configValue: typeof item[1] === "object" ? JSON.stringify(item[1]) : String(item[1])
|
||||
};
|
||||
});
|
||||
//提交数据
|
||||
sysConfigApi.configEditForm(param).finally(() => {
|
||||
submitLoading.value = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 重置表单 */
|
||||
function resetForm() {
|
||||
sysConfigFormRef.value?.resetFields();
|
||||
linkFormRef.value?.resetFields();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -0,0 +1,50 @@
|
||||
<!--
|
||||
* @Description:
|
||||
* @Author: huguodong
|
||||
* @Date: 2023-12-22 16:59:28
|
||||
!-->
|
||||
<template>
|
||||
<div class="card">
|
||||
<el-tabs v-model="activeName" class="-mt-4">
|
||||
<el-tab-pane label="系统配置" name="sysConfig"><SysBaseConfig :sys-configs="sysBase" /></el-tab-pane>
|
||||
<el-tab-pane label="安全配置" name="safety"><SafetyConfig :sys-configs="safetyConfig" /></el-tab-pane>
|
||||
<el-tab-pane label="MQTT配置" name="mqtt"><MqttConfig :sys-configs="mqttConfig" /></el-tab-pane>
|
||||
<el-tab-pane label="文件配置" name="file">开发中......</el-tab-pane>
|
||||
<el-tab-pane label="其他配置" name="other"><OtherConfig v-if="activeName === 'other'" /></el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SysBaseConfig from "./components/sysBaseConfig.vue";
|
||||
import SafetyConfig from "./components/safetyConfig/index.vue";
|
||||
import OtherConfig from "./components/otherConfig/index.vue";
|
||||
import MqttConfig from "./components/mqttConfig/index.vue";
|
||||
import { SysConfig, sysConfigApi } from "@/api";
|
||||
import { SysConfigTypeEnum } from "@/enums";
|
||||
|
||||
const activeName = ref("sysConfig");
|
||||
|
||||
const sysBase = ref<SysConfig.ConfigInfo[]>([]);
|
||||
const safetyConfig = ref<SysConfig.ConfigInfo[]>([]);
|
||||
const mqttConfig = ref<SysConfig.ConfigInfo[]>([]);
|
||||
onMounted(async () => {
|
||||
// 获取系统配置
|
||||
await sysConfigApi.list().then(res => {
|
||||
if (res.data) {
|
||||
//sysBase赋值
|
||||
sysBase.value = res.data.filter(item => item.category == SysConfigTypeEnum.SYS_BASE);
|
||||
//safetyBase赋值
|
||||
safetyConfig.value = res.data.filter(item => item.category == SysConfigTypeEnum.LOGIN_POLICY || item.category == SysConfigTypeEnum.PWD_POLICY);
|
||||
//mqttConfig赋值
|
||||
mqttConfig.value = res.data.filter(item => item.category == SysConfigTypeEnum.MQTT_POLICY);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.el-tabs__item) {
|
||||
font-size: large;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user