mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2026-02-03 00:55:33 +08:00
v3.8.2 版本前端代码
This commit is contained in:
197
jeecgboot-vue3/src/views/system/appVersion/SysAppVersion.vue
Normal file
197
jeecgboot-vue3/src/views/system/appVersion/SysAppVersion.vue
Normal file
@ -0,0 +1,197 @@
|
||||
<template>
|
||||
<PageWrapper contentFullHeight>
|
||||
<a-card :bordered="false" title="版本管理">
|
||||
<!--编辑模式-->
|
||||
<a-spin v-if="active" :spinning="confirmLoading">
|
||||
<a-form ref="formRef" :model="model" :labelCol="labelCol" :wrapperCol="wrapperCol" :rules="validatorRules">
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="版本" name="appVersion">
|
||||
<a-input v-model:value="model.appVersion" placeholder="请输入版本" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="APP安装apk" name="downloadUrl">
|
||||
<a-input placeholder="设置APP安装apk" v-model:value="model.downloadUrl">
|
||||
<template #addonAfter>
|
||||
<Icon icon="ant-design:upload-outlined" style="cursor: pointer" @click="showUploadModal('apk')" />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="APP热更新文件" name="wgtUrl">
|
||||
<a-input placeholder="设置APP热更新文件" v-model:value="model.wgtUrl">
|
||||
<template #addonAfter>
|
||||
<Icon icon="ant-design:upload-outlined" style="cursor: pointer" @click="showUploadModal('wgt')" />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item label="更新内容">
|
||||
<a-textarea :rows="4" v-model:value="model.updateNote" placeholder="请输入更新内容" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
<JUploadModal :value="modalValue" :bizPath="filePath" :maxCount="1" @register="registerModel" @change="uploadBack" />
|
||||
</a-spin>
|
||||
<!--详情模式-->
|
||||
<Description v-else class="desc" :column="1" :data="model" :schema="schema" />
|
||||
<!--底部按钮-->
|
||||
<div class="anty-form-btn" v-if="hasPermission('app:edit:version')">
|
||||
<a-button v-if="active" @click="handleSubmit" type="primary" preIcon="ant-design:save-outlined">保存</a-button>
|
||||
<a-button v-else @click="active = true" type="primary" preIcon="ant-design:edit-outlined">开启编辑模式</a-button>
|
||||
</div>
|
||||
</a-card>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="portalapp-sysAppVersion">
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { usePermission } from '@/hooks/web/usePermission';
|
||||
import { JUploadModal } from '@/components/Form/src/jeecg/components/JUpload';
|
||||
import { useModal } from '@/components/Modal';
|
||||
import { reactive, ref, toRaw, unref, onMounted } from 'vue';
|
||||
import { PageWrapper } from '@/components/Page';
|
||||
import { queryAppVersion, saveAppVersion } from './appVersion.api';
|
||||
import { Description, DescItem } from '/@/components/Description/index';
|
||||
|
||||
const { hasPermission } = usePermission();
|
||||
const { createMessage } = useMessage();
|
||||
|
||||
const [registerModel, { openModal }] = useModal();
|
||||
const confirmLoading = ref(false);
|
||||
const active = ref(false);
|
||||
const formRef = ref<any>(null);
|
||||
const appKey = 'E0CC280';
|
||||
const filePath = 'appVersion';
|
||||
const uploadType = ref('');
|
||||
const modalValue = ref('');
|
||||
const labelCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 5 },
|
||||
};
|
||||
const wrapperCol = {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 16 },
|
||||
};
|
||||
const model = reactive({
|
||||
id: 'E0CC280',
|
||||
appVersion: '',
|
||||
versionNum: 0,
|
||||
updateNote: '',
|
||||
downloadUrl: '',
|
||||
wgtUrl: '',
|
||||
});
|
||||
|
||||
/**
|
||||
* 初始化表单数据
|
||||
* @param record
|
||||
*/
|
||||
async function initFormData() {
|
||||
const appVersion = await queryAppVersion({ key: appKey });
|
||||
if (appVersion) {
|
||||
Object.assign(model, appVersion);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交保存版本信息
|
||||
*/
|
||||
function handleSubmit() {
|
||||
const form = unref(formRef);
|
||||
form.validate().then(async () => {
|
||||
let obj = toRaw(model);
|
||||
if (obj.appVersion.indexOf('.') != -1) {
|
||||
obj.versionNum = Number(obj.appVersion.replace(/\./g, ''));
|
||||
}
|
||||
obj.id = appKey;
|
||||
confirmLoading.value = true;
|
||||
await saveAppVersion(obj);
|
||||
createMessage.success('保存成功');
|
||||
confirmLoading.value = false;
|
||||
active.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示设置弹窗
|
||||
* @param type
|
||||
*/
|
||||
function showUploadModal(type) {
|
||||
uploadType.value = type;
|
||||
modalValue.value = type == 'apk' ? model.downloadUrl : model.wgtUrl;
|
||||
openModal(true, {
|
||||
maxCount: 1,
|
||||
bizPath: filePath,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*上传返回
|
||||
*/
|
||||
function uploadBack(value) {
|
||||
if (unref(uploadType) == 'apk') {
|
||||
model.downloadUrl = value;
|
||||
} else {
|
||||
model.wgtUrl = value;
|
||||
}
|
||||
}
|
||||
//表单校验规则
|
||||
const validatorRules = {
|
||||
appVersion: [{ required: true, message: '版本不能为空', trigger: 'blur' }],
|
||||
downloadUrl: [{ required: true, message: 'APP安装apk不能为空', trigger: 'change' }],
|
||||
wgtUrl: [{ required: true, message: 'APP热更新文件不能为空', trigger: 'change' }],
|
||||
};
|
||||
// 显示字段
|
||||
const schema: DescItem[] = [
|
||||
{
|
||||
field: 'appVersion',
|
||||
label: '版本',
|
||||
},
|
||||
{
|
||||
field: 'downloadUrl',
|
||||
label: 'APP安装apk',
|
||||
},
|
||||
{
|
||||
field: 'wgtUrl',
|
||||
label: 'APP热更新文件',
|
||||
},
|
||||
{
|
||||
field: 'updateNote',
|
||||
label: '更新内容',
|
||||
},
|
||||
];
|
||||
|
||||
onMounted(() => {
|
||||
initFormData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.anty-form-btn {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.anty-form-btn button {
|
||||
margin: 20px;
|
||||
}
|
||||
.approveDiv span {
|
||||
margin: 0 20px;
|
||||
}
|
||||
.desc {
|
||||
width: 80%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
:deep(.ant-descriptions-item-label) {
|
||||
width: 30% !important;
|
||||
min-width: 150px !important;
|
||||
}
|
||||
:deep(.ant-descriptions-item-content) {
|
||||
padding: 16px !important;
|
||||
width: 60% !important;
|
||||
}
|
||||
</style>
|
||||
20
jeecgboot-vue3/src/views/system/appVersion/appVersion.api.ts
Normal file
20
jeecgboot-vue3/src/views/system/appVersion/appVersion.api.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
|
||||
enum Api {
|
||||
//查询app版本
|
||||
queryAppVersion = '/sys/version/app3version',
|
||||
//保存app版本
|
||||
saveAppVersion = '/sys/version/saveVersion',
|
||||
}
|
||||
/**
|
||||
* 查询APP版本
|
||||
* @param params
|
||||
*/
|
||||
export const queryAppVersion = (params) => defHttp.get({ url: Api.queryAppVersion, params });
|
||||
/**
|
||||
* 保存APP版本
|
||||
* @param params
|
||||
*/
|
||||
export const saveAppVersion = (params) => {
|
||||
return defHttp.post({ url: Api.saveAppVersion, params });
|
||||
};
|
||||
@ -10,6 +10,7 @@ enum Api {
|
||||
wechatEnterpriseToLocal = '/sys/thirdApp/sync/wechatEnterprise/departAndUser/toLocal',
|
||||
getThirdUserBindByWechat = '/sys/thirdApp/getThirdUserBindByWechat',
|
||||
deleteThirdAccount = '/sys/thirdApp/deleteThirdAccount',
|
||||
deleteThirdAppConfig = '/sys/thirdApp/deleteThirdAppConfig',
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,4 +67,15 @@ export const getThirdUserBindByWechat = () => {
|
||||
*/
|
||||
export const deleteThirdAccount = (params) => {
|
||||
return defHttp.delete({ url: Api.deleteThirdAccount, params }, { isTransformResponse:false, joinParamsToUrl: true });
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据配置表的id删除第三方配置
|
||||
* @param params
|
||||
* @param handleSuccess
|
||||
*/
|
||||
export const deleteThirdAppConfig = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteThirdAppConfig, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
<a-collapse-panel key="2">
|
||||
<template #header>
|
||||
<div style="width: 100%; justify-content: space-between; display: flex">
|
||||
<div style="font-size: 16px"> 2.对接信息录入</div>
|
||||
<div style="font-size: 16px"> 2.对接信息录入及解绑</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="base-desc">完成步骤1后,填入Agentld、 AppKey、AppSecret后 可对接应用与同步通讯录</div>
|
||||
@ -47,6 +47,7 @@
|
||||
</div>
|
||||
<div style="margin-top: 20px; width: 100%; text-align: right">
|
||||
<a-button @click="dingEditClick">编辑</a-button>
|
||||
<a-button v-if="appConfigData.id" @click="cancelBindClick" danger style="margin-left: 10px">取消绑定</a-button>
|
||||
</div>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
@ -76,7 +77,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, h, inject, onMounted, reactive, ref, watch } from 'vue';
|
||||
import { getThirdConfigByTenantId, syncDingTalkDepartUserToLocal } from './ThirdApp.api';
|
||||
import { getThirdConfigByTenantId, syncDingTalkDepartUserToLocal, deleteThirdAppConfig } from './ThirdApp.api';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import ThirdAppConfigModal from './ThirdAppConfigModal.vue';
|
||||
import { Modal } from 'ant-design-vue';
|
||||
@ -122,6 +123,8 @@
|
||||
let values = await getThirdConfigByTenantId(params);
|
||||
if (values) {
|
||||
appConfigData.value = values;
|
||||
} else {
|
||||
appConfigData.value = "";
|
||||
}
|
||||
}
|
||||
|
||||
@ -214,6 +217,25 @@
|
||||
function handleIconClick(){
|
||||
window.open("https://help.qiaoqiaoyun.com/expand/dingdingsyn.html","_target")
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消绑定
|
||||
*/
|
||||
function cancelBindClick() {
|
||||
if(!appConfigData.value.id){
|
||||
createMessage.warning("请先绑定钉钉应用!");
|
||||
return;
|
||||
}
|
||||
Modal.confirm({
|
||||
title: '取消绑定',
|
||||
content: '是否要解除当前组织的钉钉应用配置绑定?',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
deleteThirdAppConfig({ id: appConfigData.value.id }, handleSuccess);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
let tenantId = getTenantId();
|
||||
@ -229,6 +251,7 @@
|
||||
syncDingTalk,
|
||||
btnLoading,
|
||||
handleIconClick,
|
||||
cancelBindClick,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
<a-collapse-panel key="2">
|
||||
<template #header>
|
||||
<div style="width: 100%; justify-content: space-between; display: flex">
|
||||
<div style="font-size: 16px"> 2.对接信息录入</div>
|
||||
<div style="font-size: 16px"> 2.对接信息录入及解绑</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="flex-flow">
|
||||
@ -40,6 +40,7 @@
|
||||
</div>
|
||||
<div style="margin-top: 20px; width: 100%; text-align: right">
|
||||
<a-button @click="weEnterpriseEditClick">编辑</a-button>
|
||||
<a-button v-if="appConfigData.id" @click="cancelBindClick" danger style="margin-left: 10px">取消绑定</a-button>
|
||||
</div>
|
||||
</a-collapse-panel>
|
||||
</a-collapse>
|
||||
@ -61,7 +62,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, ref } from 'vue';
|
||||
import { getThirdConfigByTenantId } from './ThirdApp.api';
|
||||
import { getThirdConfigByTenantId, deleteThirdAppConfig } from './ThirdApp.api';
|
||||
import ThirdAppConfigModal from './ThirdAppConfigModal.vue';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
@ -97,6 +98,8 @@
|
||||
let values = await getThirdConfigByTenantId(params);
|
||||
if (values) {
|
||||
appConfigData.value = values;
|
||||
} else {
|
||||
appConfigData.value = "";
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,6 +162,25 @@
|
||||
function seeBindWeChat() {
|
||||
openBindModal(true,{ izBind: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消绑定
|
||||
*/
|
||||
function cancelBindClick() {
|
||||
if(!appConfigData.value.id){
|
||||
createMessage.warning("请先绑定企业微信应用!");
|
||||
return;
|
||||
}
|
||||
Modal.confirm({
|
||||
title: '取消绑定',
|
||||
content: '是否要解除当前组织的企业微信应用配置绑定?',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
deleteThirdAppConfig({ id: appConfigData.value.id }, handleSuccess);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
let tenantId = getTenantId();
|
||||
@ -175,6 +197,7 @@
|
||||
thirdUserByWechat,
|
||||
handleBindSuccess,
|
||||
seeBindWeChat,
|
||||
cancelBindClick,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" title="首页配置" @ok="handleSubmit" :width="600">
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, unref } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { formSchema } from '../home.data';
|
||||
import { saveOrUpdate } from '../home.api';
|
||||
// Emits声明
|
||||
const emit = defineEmits(['register', 'success']);
|
||||
const isUpdate = ref(false);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
labelWidth: 100,
|
||||
baseRowStyle: { marginTop: '10px' },
|
||||
schemas: formSchema,
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
//重置表单
|
||||
await resetFields();
|
||||
setModalProps({ confirmLoading: false });
|
||||
isUpdate.value = !!data?.isUpdate;
|
||||
if (unref(isUpdate)) {
|
||||
//表单赋值
|
||||
if (data.values.relationType == 'USER') {
|
||||
data.values.userCode = data.values.roleCode;
|
||||
}
|
||||
await setFieldsValue({
|
||||
...data.values,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//表单提交事件
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
let values = await validate();
|
||||
setModalProps({ confirmLoading: true });
|
||||
//提交表单
|
||||
if(values.relationType == 'USER'){
|
||||
values.roleCode = values.userCode;
|
||||
}
|
||||
await saveOrUpdate(values, isUpdate.value);
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
//刷新列表
|
||||
emit('success');
|
||||
} finally {
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
55
jeecgboot-vue3/src/views/system/homeConfig/home.api.ts
Normal file
55
jeecgboot-vue3/src/views/system/homeConfig/home.api.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { Modal } from 'ant-design-vue';
|
||||
|
||||
enum Api {
|
||||
list = '/sys/sysRoleIndex/list',
|
||||
save = '/sys/sysRoleIndex/add',
|
||||
edit = '/sys/sysRoleIndex/edit',
|
||||
deleteIndex = '/sys/sysRoleIndex/delete',
|
||||
deleteBatch = '/sys/sysRoleIndex/deleteBatch',
|
||||
queryIndexByCode = '/sys/sysRoleIndex/queryByCode',
|
||||
}
|
||||
/**
|
||||
* 系统角色列表
|
||||
* @param params
|
||||
*/
|
||||
export const list = (params) => defHttp.get({ url: Api.list, params });
|
||||
|
||||
/**
|
||||
* 删除角色
|
||||
*/
|
||||
export const deleteIndex = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteIndex, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 批量删除角色
|
||||
* @param params
|
||||
*/
|
||||
export const batchDelete = (params, handleSuccess) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 保存或者更新首页配置
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate) => {
|
||||
const url = isUpdate ? Api.edit : Api.save;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
/**
|
||||
* 查询首页配置
|
||||
* @param params
|
||||
*/
|
||||
export const queryIndexByCode = (params) => defHttp.get({ url: Api.queryIndexByCode, params }, { isTransformResponse: false });
|
||||
129
jeecgboot-vue3/src/views/system/homeConfig/home.data.ts
Normal file
129
jeecgboot-vue3/src/views/system/homeConfig/home.data.ts
Normal file
@ -0,0 +1,129 @@
|
||||
import { FormSchema } from '/@/components/Table';
|
||||
|
||||
//列配置
|
||||
export const columns = [
|
||||
{
|
||||
title: '关联类型(用户/角色)',
|
||||
dataIndex: 'relationType_dictText',
|
||||
width: 80,
|
||||
slots: { customRender: 'relationType' },
|
||||
},
|
||||
{
|
||||
title: '用户/角色编码',
|
||||
dataIndex: 'roleCode',
|
||||
width: 80,
|
||||
slots: { customRender: 'roleCode' },
|
||||
},
|
||||
{
|
||||
title: '首页路由',
|
||||
dataIndex: 'url',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '组件地址',
|
||||
dataIndex: 'component',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '是否开启',
|
||||
dataIndex: 'status',
|
||||
slots: { customRender: 'status' },
|
||||
width: 60,
|
||||
},
|
||||
];
|
||||
//查询配置
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'relationType',
|
||||
label: '关联类型',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
dictCode: 'relation_type',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'route',
|
||||
label: '是否路由菜单',
|
||||
helpMessage: '非路由菜单设置成首页,需开启',
|
||||
component: 'Switch',
|
||||
show: false,
|
||||
},
|
||||
];
|
||||
|
||||
export const formSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'id',
|
||||
label: '',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
field: 'relationType',
|
||||
label: '关联类型',
|
||||
component: 'JDictSelectTag',
|
||||
required: true,
|
||||
defaultValue: 'ROLE',
|
||||
componentProps: {
|
||||
dictCode: 'relation_type',
|
||||
type: 'radioButton',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '角色编码',
|
||||
field: 'roleCode',
|
||||
component: 'JSelectRole',
|
||||
required: true,
|
||||
componentProps: {
|
||||
rowKey: 'roleCode',
|
||||
isRadioSelection: true,
|
||||
},
|
||||
ifShow: ({ values }) => values.relationType == 'ROLE',
|
||||
},
|
||||
{
|
||||
label: '用户编码',
|
||||
field: 'userCode',
|
||||
component: 'JSelectUser',
|
||||
required: true,
|
||||
componentProps: {
|
||||
isRadioSelection: true,
|
||||
},
|
||||
ifShow: ({ values }) => values.relationType == 'USER',
|
||||
},
|
||||
{
|
||||
label: '首页路由',
|
||||
field: 'url',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: '组件地址',
|
||||
field: 'component',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入前端组件',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: '优先级',
|
||||
field: 'priority',
|
||||
component: 'InputNumber',
|
||||
},
|
||||
{
|
||||
field: 'route',
|
||||
label: '是否路由菜单',
|
||||
helpMessage: '非路由菜单设置成首页,需开启',
|
||||
component: 'Switch',
|
||||
defaultValue: true,
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
label: '是否开启',
|
||||
field: 'status',
|
||||
component: 'JSwitch',
|
||||
defaultValue: '1',
|
||||
componentProps: {
|
||||
options: ['1', '0'],
|
||||
},
|
||||
},
|
||||
];
|
||||
126
jeecgboot-vue3/src/views/system/homeConfig/index.vue
Normal file
126
jeecgboot-vue3/src/views/system/homeConfig/index.vue
Normal file
@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<div>
|
||||
<BasicTable @register="registerTable" :rowSelection="rowSelection">
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate">新增</a-button>
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="batchHandleDelete">
|
||||
<Icon icon="ant-design:delete-outlined" /> 删除
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button>批量操作<Icon icon="mdi:chevron-down" /></a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" />
|
||||
</template>
|
||||
<template #status="{ text }">
|
||||
<a-tag color="pink" v-if="text == 0">禁用</a-tag>
|
||||
<a-tag color="#87d068" v-if="text == 1">启用</a-tag>
|
||||
</template>
|
||||
<template #relationType="{ text, record }">
|
||||
<span>{{ record.roleCode == 'DEF_INDEX_ALL' ? '--' : text }}</span>
|
||||
</template>
|
||||
<template #roleCode="{ text, record }">
|
||||
<span>{{ record.roleCode == 'DEF_INDEX_ALL' ? '菜单默认首页' : text }}</span>
|
||||
</template>
|
||||
</BasicTable>
|
||||
<!--角色首页配置-->
|
||||
<HomeConfigModal @register="register" @success="reload" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" name="home-config" setup>
|
||||
import { BasicTable, TableAction } from '/@/components/Table';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import HomeConfigModal from './components/HomeConfigModal.vue';
|
||||
import { columns, searchFormSchema } from './home.data';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { list, deleteIndex, batchDelete } from './home.api';
|
||||
|
||||
//弹窗配置
|
||||
const [register, { openModal }] = useModal();
|
||||
|
||||
// 列表页面公共参数、方法
|
||||
const { tableContext } = useListPage({
|
||||
designScope: 'home-config',
|
||||
tableProps: {
|
||||
title: '首页配置',
|
||||
api: list,
|
||||
columns: columns,
|
||||
formConfig: {
|
||||
labelAlign: 'left',
|
||||
labelWidth: 80,
|
||||
schemas: searchFormSchema,
|
||||
baseRowStyle: {
|
||||
marginLeft: '2px',
|
||||
},
|
||||
},
|
||||
actionColumn: {
|
||||
width: 80,
|
||||
},
|
||||
//自定义默认排序
|
||||
defSort: {
|
||||
column: 'id',
|
||||
order: 'desc',
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload, clearSelectedRowKeys }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
|
||||
/**
|
||||
* 新增事件
|
||||
*/
|
||||
async function handleCreate() {
|
||||
openModal(true, {
|
||||
isUpdate: false,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 编辑事件
|
||||
*/
|
||||
async function handleEdit(record) {
|
||||
openModal(true, {
|
||||
isUpdate: true,
|
||||
values: record,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 删除事件
|
||||
*/
|
||||
async function handleDelete(record) {
|
||||
await deleteIndex({ id: record.id }, () => {
|
||||
reload();
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 批量删除事件
|
||||
*/
|
||||
async function batchHandleDelete() {
|
||||
await batchDelete({ ids: selectedRowKeys.value }, () => {
|
||||
clearSelectedRowKeys();
|
||||
reload();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record) {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record),
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
@ -344,7 +344,9 @@
|
||||
return;
|
||||
}
|
||||
//update-begin---author:wangshuai---date:2024-04-18---for:【QQYUN-9005】同一个IP,1分钟超过5次短信,则提示需要验证码---
|
||||
const result = await getCaptcha({ mobile: phoneFormData.mobile, smsmode: SmsEnum.FORGET_PASSWORD }).catch((res) =>{
|
||||
//update-begin---author:wangshuai---date:2025-07-15---for:【issues/8567】严重:修改密码存在水平越权问题:登录应该用登录模板不应该用忘记密码的模板---
|
||||
const result = await getCaptcha({ mobile: phoneFormData.mobile, smsmode: SmsEnum.LOGIN }).catch((res) =>{
|
||||
//update-end---author:wangshuai---date:2025-07-15---for:【issues/8567】严重:修改密码存在水平越权问题:登录应该用登录模板不应该用忘记密码的模板---
|
||||
if(res.code === ExceptionEnum.PHONE_SMS_FAIL_CODE){
|
||||
openCaptchaModal(true, {});
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<BasicModal @register="registerModal" :title="title" :width="800" v-bind="$attrs" @ok="onSubmit">
|
||||
<BasicModal @register="registerModal" :title="title" :width="600" v-bind="$attrs" @ok="onSubmit">
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
@ -21,6 +21,15 @@
|
||||
//update-end---author:wangshuai ---date:20221123 for:[VUEN-2807]消息模板加一个查看功能--------------z
|
||||
schemas: formSchemas,
|
||||
showActionButtonGroup: false,
|
||||
baseRowStyle: {
|
||||
marginTop: '10px',
|
||||
},
|
||||
labelCol: {
|
||||
span: 5,
|
||||
},
|
||||
wrapperCol: {
|
||||
span: 17,
|
||||
},
|
||||
});
|
||||
// 注册 modal
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
|
||||
@ -86,12 +86,23 @@ export const formSchemas: FormSchema[] = [
|
||||
label: '模板类型',
|
||||
field: 'templateType',
|
||||
component: 'JDictSelectTag',
|
||||
defaultValue: '1',
|
||||
componentProps: {
|
||||
dictCode: 'msgType',
|
||||
type: 'radio',
|
||||
placeholder: '请选择模板类型',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
label: '模板分类',
|
||||
field: 'templateCategory',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
dictCode: 'msgCategory',
|
||||
placeholder: '请选择模板分类',
|
||||
}
|
||||
},
|
||||
{
|
||||
label: '是否应用',
|
||||
field: 'useStatus',
|
||||
|
||||
@ -1,20 +1,113 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" title="查看详情" :showCancelBtn="false" :showOkBtn="false" :maxHeight="500">
|
||||
<iframe :src="frameSrc" class="detail-iframe" />
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :width="800" title="查看详情" :showCancelBtn="false" :showOkBtn="false" :maxHeight="500">
|
||||
<div class="print-btn" @click="onPrinter">
|
||||
<Icon icon="ant-design:printer-filled" />
|
||||
<span class="print-text">打印</span>
|
||||
</div>
|
||||
<iframe ref="iframeRef" :src="frameSrc" class="detail-iframe" @load="onIframeLoad"></iframe>
|
||||
<template v-if="noticeFiles && noticeFiles.length > 0">
|
||||
<div class="files-title">相关附件:</div>
|
||||
<template v-for="(file, index) in noticeFiles" :key="index">
|
||||
<div class="files-area">
|
||||
<div class="files-area-text">
|
||||
<span>
|
||||
<paper-clip-outlined />
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
:title="file.fileName"
|
||||
:href="getFileAccessHttpUrl(file.filePath)"
|
||||
class="ant-upload-list-item-name"
|
||||
>{{ file.fileName }}</a
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
<div class="files-area-operate">
|
||||
<download-outlined class="item-icon" @click="handleDownloadFile(file.filePath)" />
|
||||
<eye-outlined class="item-icon" @click="handleViewFile(file.filePath)" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
import { ref } from 'vue';
|
||||
import { buildUUID } from '@/utils/uuid';
|
||||
import { getFileAccessHttpUrl } from '@/utils/common/compUtils';
|
||||
import { DownloadOutlined, EyeOutlined, PaperClipOutlined } from '@ant-design/icons-vue';
|
||||
import { encryptByBase64 } from '@/utils/cipher';
|
||||
import { useGlobSetting } from '@/hooks/setting';
|
||||
const glob = useGlobSetting();
|
||||
// 获取props
|
||||
defineProps({
|
||||
frameSrc: propTypes.string.def(''),
|
||||
});
|
||||
//附件内容
|
||||
const noticeFiles = ref([]);
|
||||
//表单赋值
|
||||
const [registerModal] = useModalInner();
|
||||
const [registerModal] = useModalInner((data) => {
|
||||
noticeFiles.value = [];
|
||||
if (data.record?.files && data.record?.files.length > 0) {
|
||||
noticeFiles.value = data.record.files.split(',').map((item) => {
|
||||
return {
|
||||
fileName: item.split('/').pop(),
|
||||
filePath: item,
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
// iframe引用
|
||||
const iframeRef = ref<HTMLIFrameElement>();
|
||||
// 存储当前打印会话ID
|
||||
const printSessionId = ref<string>('');
|
||||
// iframe加载完成后初始化通信
|
||||
const onIframeLoad = () => {
|
||||
printSessionId.value = buildUUID(); // 每次加载生成新的会话ID
|
||||
};
|
||||
//打印
|
||||
function onPrinter() {
|
||||
if (!iframeRef.value) return;
|
||||
console.log('onPrinter', iframeRef.value);
|
||||
iframeRef.value?.contentWindow?.postMessage({ printSessionId: printSessionId.value, type: 'action:print' }, '*');
|
||||
}
|
||||
/**
|
||||
* 下载文件
|
||||
* @param filePath
|
||||
*/
|
||||
function handleDownloadFile(filePath) {
|
||||
window.open(getFileAccessHttpUrl(filePath), '_blank');
|
||||
}
|
||||
/**
|
||||
* 预览文件
|
||||
* @param filePath
|
||||
*/
|
||||
function handleViewFile(filePath) {
|
||||
if (filePath) {
|
||||
let url = encodeURIComponent(encryptByBase64(filePath));
|
||||
let previewUrl = `${glob.viewUrl}?url=` + url;
|
||||
window.open(previewUrl, '_blank');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.print-btn {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
cursor: pointer;
|
||||
color: #a3a3a5;
|
||||
z-index: 999;
|
||||
.print-text {
|
||||
margin-left: 5px;
|
||||
}
|
||||
&:hover {
|
||||
color: #40a9ff;
|
||||
}
|
||||
}
|
||||
.detail-iframe {
|
||||
border: 0;
|
||||
width: 100%;
|
||||
@ -24,4 +117,37 @@
|
||||
display: block;
|
||||
// -update-end--author:liaozhiyang---date:20240702---for:【TV360X-1685】通知公告查看出现两个滚动条
|
||||
}
|
||||
.files-title {
|
||||
font-size: 16px;
|
||||
margin: 10px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
.files-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
margin: 6px;
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.files-area-text {
|
||||
display: flex;
|
||||
.ant-upload-list-item-name {
|
||||
margin: 0 6px;
|
||||
color: #56befa;
|
||||
}
|
||||
}
|
||||
.files-area-operate {
|
||||
display: flex;
|
||||
margin-left: 10px;
|
||||
.item-icon {
|
||||
cursor: pointer;
|
||||
margin: 0 6px;
|
||||
&:hover {
|
||||
color: #56befa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
116
jeecgboot-vue3/src/views/system/notice/NoticeForm.vue
Normal file
116
jeecgboot-vue3/src/views/system/notice/NoticeForm.vue
Normal file
@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div style="min-height: 400px">
|
||||
<BasicForm @register="registerForm">
|
||||
<template #msgTemplate="{ model, field }">
|
||||
<a-select v-model:value="model[field]" placeholder="请选择消息模版" :options="templateOption" @change="handleChange" />
|
||||
</template>
|
||||
<template #msgContent="{ model, field }">
|
||||
<div v-html="model[field]" class="article-content"></div>
|
||||
</template>
|
||||
</BasicForm>
|
||||
<div class="footer-btn" v-if="!formDisabled">
|
||||
<a-button @click="submitForm" pre-icon="ant-design:check" type="primary">提 交</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { getBpmFormSchema } from './notice.data';
|
||||
import { getTempList, queryById, saveOrUpdate } from './notice.api';
|
||||
import { computed, ref } from 'vue';
|
||||
// 定义属性
|
||||
const props = defineProps({
|
||||
formData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
//表单禁用
|
||||
const formDisabled = computed(() => {
|
||||
if (props.formData.disabled === false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
const templateOption = ref([]);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
schemas: getBpmFormSchema(props.formData),
|
||||
showActionButtonGroup: false,
|
||||
disabled: formDisabled.value,
|
||||
labelWidth: 100,
|
||||
baseRowStyle: { marginTop: '10px' },
|
||||
baseColProps: { xs: 24, sm: 12, md: 12, lg: 12, xl: 12, xxl: 12 },
|
||||
});
|
||||
|
||||
//表单提交
|
||||
async function submitForm() {
|
||||
let values = await validate();
|
||||
if (values.msgType === 'ALL') {
|
||||
values.userIds = '';
|
||||
} else {
|
||||
values.userIds += ',';
|
||||
}
|
||||
console.log('表单数据', values);
|
||||
await saveOrUpdate(values, true);
|
||||
}
|
||||
//初始化模板
|
||||
async function initTemplate() {
|
||||
const res = await getTempList({ templateCategory: 'notice', pageSize: 100 });
|
||||
console.log('res', res);
|
||||
if (res.records && res.records.length > 0) {
|
||||
templateOption.value = res.records.map((item) => {
|
||||
return {
|
||||
label: item.templateName,
|
||||
value: item.templateCode,
|
||||
content: item.templateContent,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 模版修改
|
||||
* @param val
|
||||
*/
|
||||
function handleChange(val) {
|
||||
const content = templateOption.value.find((item: any) => item.value === val)?.content;
|
||||
if (content) {
|
||||
setFieldsValue({
|
||||
msgContent: content,
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 加载数据
|
||||
*/
|
||||
async function initFormData() {
|
||||
let res = await queryById({ id: props.formData.dataId });
|
||||
if (res.success) {
|
||||
//重置表单
|
||||
await resetFields();
|
||||
const record = res.result;
|
||||
if (record.userIds) {
|
||||
record.userIds = record.userIds.substring(0, record.userIds.length - 1);
|
||||
}
|
||||
//表单赋值
|
||||
await setFieldsValue({
|
||||
...record,
|
||||
});
|
||||
}
|
||||
}
|
||||
//加载模版
|
||||
initTemplate();
|
||||
//加载数据
|
||||
initFormData();
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.footer-btn {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.article-content {
|
||||
max-width: 100%;
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
@ -1,6 +1,19 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="900px" destroyOnClose>
|
||||
<BasicForm @register="registerForm" />
|
||||
<BasicModal
|
||||
v-bind="$attrs"
|
||||
@register="registerModal"
|
||||
@ok="handleSubmit"
|
||||
:title="title"
|
||||
width="900px"
|
||||
wrapClassName="notice-cls-modal"
|
||||
:maxHeight="800"
|
||||
destroyOnClose
|
||||
>
|
||||
<BasicForm @register="registerForm">
|
||||
<template #msgTemplate="{ model, field }">
|
||||
<a-select v-model:value="model[field]" placeholder="请选择消息模版" :options="templateOption" @change="handleChange" />
|
||||
</template>
|
||||
</BasicForm>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
@ -8,17 +21,24 @@
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { formSchema } from './notice.data';
|
||||
import { saveOrUpdate } from './notice.api';
|
||||
import { getTempList, saveOrUpdate } from './notice.api';
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['register', 'success']);
|
||||
const isUpdate = ref(true);
|
||||
const record = ref<any>({});
|
||||
const templateOption = ref([]);
|
||||
//表单配置
|
||||
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
|
||||
schemas: formSchema,
|
||||
showActionButtonGroup: false,
|
||||
labelWidth: 100,
|
||||
baseRowStyle: { marginTop: '10px' },
|
||||
baseColProps: { xs: 24, sm: 12, md: 12, lg: 12, xl: 12, xxl: 12 },
|
||||
});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
//加载模版
|
||||
await initTemplate();
|
||||
//重置表单
|
||||
await resetFields();
|
||||
setModalProps({ confirmLoading: false });
|
||||
@ -31,12 +51,13 @@
|
||||
await setFieldsValue({
|
||||
...data.record,
|
||||
});
|
||||
record.value = data.record;
|
||||
}
|
||||
});
|
||||
//设置标题
|
||||
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
|
||||
//表单提交事件
|
||||
async function handleSubmit(v) {
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
let values = await validate();
|
||||
setModalProps({ confirmLoading: true });
|
||||
@ -48,7 +69,7 @@
|
||||
values.userIds += ',';
|
||||
}
|
||||
//update-end-author:liusq---date:20230404--for: [issue#429]新增通知公告提交指定用户参数有undefined ---
|
||||
if (isUpdate.value) {
|
||||
if (isUpdate.value && record.value.sendStatus != '2') {
|
||||
values.sendStatus = '0';
|
||||
}
|
||||
await saveOrUpdate(values, isUpdate.value);
|
||||
@ -60,4 +81,36 @@
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
//初始化模板
|
||||
async function initTemplate() {
|
||||
const res = await getTempList({ templateCategory: 'notice', pageSize: 100 });
|
||||
console.log('res', res);
|
||||
if (res.records && res.records.length > 0) {
|
||||
templateOption.value = res.records.map((item) => {
|
||||
return {
|
||||
label: item.templateName,
|
||||
value: item.templateCode,
|
||||
content: item.templateContent,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 模版修改
|
||||
* @param val
|
||||
*/
|
||||
function handleChange(val) {
|
||||
const content = templateOption.value.find((item: any) => item.value === val)?.content;
|
||||
if (content) {
|
||||
setFieldsValue({
|
||||
msgContent: content,
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.notice-cls-modal {
|
||||
top: 20px !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -34,17 +34,17 @@
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import NoticeModal from './NoticeModal.vue';
|
||||
import DetailModal from './DetailModal.vue';
|
||||
import { useMethods } from '/@/hooks/system/useMethods';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { useGlobSetting } from '/@/hooks/setting';
|
||||
import { getToken } from '/@/utils/auth';
|
||||
import { columns, searchFormSchema } from './notice.data';
|
||||
import { getList, deleteNotice, batchDeleteNotice, getExportUrl, getImportUrl, doReleaseData, doReovkeData } from './notice.api';
|
||||
import { getList, deleteNotice, batchDeleteNotice,editIzTop, getExportUrl, getImportUrl, doReleaseData, doReovkeData } from './notice.api';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
const glob = useGlobSetting();
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
const [register, { openModal: openDetail }] = useModal();
|
||||
const iframeUrl = ref('');
|
||||
|
||||
const { createMessage, createConfirm } = useMessage();
|
||||
// 列表页面公共参数、方法
|
||||
const { prefixCls, onExportXls, onImportXls, tableContext, doRequest } = useListPage({
|
||||
designScope: 'notice-template',
|
||||
@ -66,7 +66,8 @@
|
||||
});
|
||||
|
||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||
|
||||
//流程编码
|
||||
const flowCode = 'dev_sys_announcement_001';
|
||||
/**
|
||||
* 新增事件
|
||||
*/
|
||||
@ -92,6 +93,12 @@
|
||||
async function handleDelete(record) {
|
||||
await deleteNotice({ id: record.id }, reload);
|
||||
}
|
||||
/**
|
||||
* 置顶操作
|
||||
*/
|
||||
async function handleTop(record, izTop) {
|
||||
await editIzTop({ id: record.id, izTop }, reload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除事件
|
||||
@ -118,8 +125,9 @@
|
||||
*/
|
||||
function handleDetail(record) {
|
||||
iframeUrl.value = `${glob.uploadUrl}/sys/annountCement/show/${record.id}?token=${getToken()}`;
|
||||
openDetail(true);
|
||||
openDetail(true, { record });
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作列定义
|
||||
* @param record
|
||||
@ -131,6 +139,11 @@
|
||||
onClick: handleEdit.bind(null, record),
|
||||
ifShow: record.sendStatus == 0 || record.sendStatus == '2',
|
||||
},
|
||||
{
|
||||
label: '查看',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
ifShow: record.sendStatus == 1,
|
||||
},
|
||||
];
|
||||
}
|
||||
/**
|
||||
@ -148,7 +161,7 @@
|
||||
},
|
||||
{
|
||||
label: '发布',
|
||||
ifShow: record.sendStatus == 0,
|
||||
ifShow: (!record?.izApproval || record.izApproval == '0') && record.sendStatus == 0,
|
||||
onClick: handleRelease.bind(null, record.id),
|
||||
},
|
||||
{
|
||||
@ -160,8 +173,22 @@
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '查看',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
label: '发布',
|
||||
ifShow: record.sendStatus == '2',
|
||||
popConfirm: {
|
||||
title: '确定要再次发布吗?',
|
||||
confirm: handleRelease.bind(null, record.id),
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '置顶',
|
||||
onClick: handleTop.bind(null, record, 1),
|
||||
ifShow: record.sendStatus == 1 && record.izTop == 0,
|
||||
},
|
||||
{
|
||||
label: '取消置顶',
|
||||
onClick: handleTop.bind(null, record, 0),
|
||||
ifShow: record.sendStatus == 1 && record.izTop == 1,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@ -5,11 +5,17 @@ enum Api {
|
||||
save = '/sys/annountCement/add',
|
||||
edit = '/sys/annountCement/edit',
|
||||
delete = '/sys/annountCement/delete',
|
||||
queryById = '/sys/annountCement/queryById',
|
||||
deleteBatch = '/sys/annountCement/deleteBatch',
|
||||
exportXls = '/sys/annountCement/exportXls',
|
||||
importExcel = '/sys/annountCement/importExcel',
|
||||
releaseData = '/sys/annountCement/doReleaseData',
|
||||
reovkeData = '/sys/annountCement/doReovkeData',
|
||||
editIzTop = '/sys/annountCement/editIzTop',
|
||||
|
||||
addVisitsNum = '/sys/annountCement/addVisitsNumber',
|
||||
|
||||
tempList = '/sys/message/sysMessageTemplate/list',
|
||||
}
|
||||
|
||||
/**
|
||||
@ -21,7 +27,7 @@ export const getExportUrl = Api.exportXls;
|
||||
*/
|
||||
export const getImportUrl = Api.importExcel;
|
||||
/**
|
||||
* 查询租户列表
|
||||
* 查询消息列表
|
||||
* @param params
|
||||
*/
|
||||
export const getList = (params) => {
|
||||
@ -33,7 +39,7 @@ export const getList = (params) => {
|
||||
* @param params
|
||||
*/
|
||||
export const saveOrUpdate = (params, isUpdate) => {
|
||||
let url = isUpdate ? Api.edit : Api.save;
|
||||
const url = isUpdate ? Api.edit : Api.save;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
|
||||
@ -46,6 +52,15 @@ export const deleteNotice = (params, handleSuccess) => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 置顶编辑
|
||||
* @param params
|
||||
*/
|
||||
export const editIzTop = (params, handleSuccess) => {
|
||||
return defHttp.post({ url: Api.editIzTop, data: params }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量消息公告
|
||||
@ -63,3 +78,26 @@ export const doReleaseData = (params) => defHttp.get({ url: Api.releaseData, par
|
||||
* @param id
|
||||
*/
|
||||
export const doReovkeData = (params) => defHttp.get({ url: Api.reovkeData, params });
|
||||
/**
|
||||
* 新增访问量
|
||||
* @param id
|
||||
*/
|
||||
export const addVisitsNum = (params) => defHttp.get({ url: Api.addVisitsNum, params }, { successMessageMode: 'none' });
|
||||
/**
|
||||
* 根据ID查询数据
|
||||
* @param id
|
||||
*/
|
||||
export const queryById = (params) => defHttp.get({ url: Api.queryById, params }, { isTransformResponse: false });
|
||||
/**
|
||||
* 发起流程
|
||||
* import { startProcess } from '/@/api/common/api';
|
||||
* @param params
|
||||
*/
|
||||
export const startProcess = (params) => defHttp.post({ url: Api.startProcess, params }, { isTransformResponse: false });
|
||||
/**
|
||||
* 查询模板列表
|
||||
* @param params
|
||||
*/
|
||||
export const getTempList = (params) => {
|
||||
return defHttp.get({ url: Api.tempList, params });
|
||||
};
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { BasicColumn, FormSchema } from '/@/components/Table';
|
||||
import { rules } from '/@/utils/helper/validator';
|
||||
import { render } from '/@/utils/common/renderUtils';
|
||||
import { h } from 'vue';
|
||||
import { Tinymce } from '@/components/Tinymce';
|
||||
|
||||
export const columns: BasicColumn[] = [
|
||||
{
|
||||
@ -87,9 +88,24 @@ export const formSchema: FormSchema[] = [
|
||||
placeholder: '请选择类型',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'izTop',
|
||||
label: '是否置顶',
|
||||
defaultValue: '0',
|
||||
component: 'JSwitch',
|
||||
componentProps: {
|
||||
//取值 options
|
||||
options: ['1', '0'],
|
||||
//文本option
|
||||
labelOptions: ['是', '否'],
|
||||
placeholder: '是否置顶',
|
||||
checkedChildren: '是',
|
||||
unCheckedChildren: '否',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'titile',
|
||||
label: '标题',
|
||||
label: '通告标题',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
componentProps: {
|
||||
@ -114,8 +130,15 @@ export const formSchema: FormSchema[] = [
|
||||
},
|
||||
{
|
||||
field: 'msgAbstract',
|
||||
label: '摘要',
|
||||
label: '通告摘要',
|
||||
component: 'InputTextArea',
|
||||
componentProps: {
|
||||
allowClear: true,
|
||||
autoSize: {
|
||||
minRows: 2,
|
||||
maxRows: 5,
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
// {
|
||||
@ -154,9 +177,18 @@ export const formSchema: FormSchema[] = [
|
||||
},
|
||||
ifShow: ({ values }) => values.msgType == 'USER',
|
||||
},
|
||||
{
|
||||
field: 'msgClassify',
|
||||
label: '公告分类',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
dictCode: 'notice_type',
|
||||
placeholder: '请选择公告分类',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'priority',
|
||||
label: '优先级',
|
||||
label: '优先级别',
|
||||
defaultValue: 'H',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
@ -166,9 +198,211 @@ export const formSchema: FormSchema[] = [
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'msgContent',
|
||||
label: '内容',
|
||||
field: 'izApproval',
|
||||
label: '是否审批',
|
||||
component: 'RadioGroup',
|
||||
defaultValue: '0',
|
||||
componentProps: {
|
||||
options: [
|
||||
{
|
||||
label: '是',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '否',
|
||||
value: '0',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'msgTemplate',
|
||||
label: '公告模版',
|
||||
component: 'Input',
|
||||
slot: 'msgTemplate',
|
||||
},
|
||||
{
|
||||
field: 'files',
|
||||
label: '通告附件',
|
||||
component: 'JUpload',
|
||||
componentProps: {
|
||||
//是否显示选择按钮
|
||||
text: '文件上传',
|
||||
//最大上传数
|
||||
maxCount: 20,
|
||||
//是否显示下载按钮
|
||||
download: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'msgContent',
|
||||
label: '通告内容',
|
||||
component: 'Input',
|
||||
colProps: { span: 24 },
|
||||
render: render.renderTinymce,
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* 流程表单调用这个方法获取formSchema
|
||||
* @param param
|
||||
*/
|
||||
export function getBpmFormSchema(_formData): FormSchema[] {
|
||||
// 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
|
||||
return [
|
||||
{
|
||||
field: 'id',
|
||||
label: 'id',
|
||||
component: 'Input',
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
field: 'msgCategory',
|
||||
label: '消息类型',
|
||||
required: true,
|
||||
component: 'JDictSelectTag',
|
||||
defaultValue: '1',
|
||||
componentProps: {
|
||||
type: 'radio',
|
||||
dictCode: 'msg_category',
|
||||
placeholder: '请选择类型',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'izTop',
|
||||
label: '是否置顶',
|
||||
defaultValue: '0',
|
||||
component: 'JSwitch',
|
||||
componentProps: {
|
||||
//取值 options
|
||||
options: ['1', '0'],
|
||||
//文本option
|
||||
labelOptions: ['是', '否'],
|
||||
placeholder: '是否置顶',
|
||||
checkedChildren: '是',
|
||||
unCheckedChildren: '否',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'titile',
|
||||
label: '通告标题',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
componentProps: {
|
||||
placeholder: '请输入标题',
|
||||
},
|
||||
// update-begin--author:liaozhiyang---date:20240701---for:【TV360X-1632】标题过长保存报错,长度校验
|
||||
dynamicRules() {
|
||||
return [
|
||||
{
|
||||
validator: (_, value) => {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
if (value.length > 100) {
|
||||
reject('最长100个字符');
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
// update-end--author:liaozhiyang---date:20240701---for:【TV360X-1632】标题过长保存报错,长度校验
|
||||
},
|
||||
{
|
||||
field: 'msgAbstract',
|
||||
label: '通告摘要',
|
||||
component: 'InputTextArea',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: 'msgType',
|
||||
label: '接收用户',
|
||||
defaultValue: 'ALL',
|
||||
component: 'JDictSelectTag',
|
||||
required: true,
|
||||
componentProps: {
|
||||
type: 'radio',
|
||||
dictCode: 'msg_type',
|
||||
placeholder: '请选择发布范围',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'userIds',
|
||||
label: '指定用户',
|
||||
component: 'JSelectUserByDepartment',
|
||||
required: true,
|
||||
componentProps: {
|
||||
rowKey: 'id',
|
||||
// update-begin--author:liaozhiyang---date:20240701---for:【TV360X-1627】通知公告用户选择组件没翻译
|
||||
labelKey: 'realname',
|
||||
// update-end--author:liaozhiyang---date:20240701---for:【TV360X-1627】通知公告用户选择组件没翻译
|
||||
},
|
||||
ifShow: ({ values }) => values.msgType == 'USER',
|
||||
},
|
||||
{
|
||||
field: 'msgClassify',
|
||||
label: '公告分类',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
dictCode: 'notice_type',
|
||||
placeholder: '请选择公告分类',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'priority',
|
||||
label: '优先级别',
|
||||
defaultValue: 'H',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
dictCode: 'priority',
|
||||
type: 'radio',
|
||||
placeholder: '请选择优先级',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'msgTemplate',
|
||||
label: '公告模版',
|
||||
component: 'Input',
|
||||
slot: 'msgTemplate',
|
||||
},
|
||||
{
|
||||
field: 'files',
|
||||
label: '通告附件',
|
||||
component: 'JUpload',
|
||||
componentProps: {
|
||||
//是否显示选择按钮
|
||||
text: '文件上传',
|
||||
//最大上传数
|
||||
maxCount: 2,
|
||||
//是否显示下载按钮
|
||||
download: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'msgContent',
|
||||
label: '通告内容',
|
||||
component: 'Input',
|
||||
colProps: { span: 24 },
|
||||
ifShow: ({}) => _formData.disabled == false,
|
||||
render: ({ model, field }) => {
|
||||
return h(Tinymce, {
|
||||
showImageUpload: false,
|
||||
disabled: _formData.disabled !== false,
|
||||
height: 300,
|
||||
value: model[field],
|
||||
onChange: (value: string) => {
|
||||
model[field] = value;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'msgContent',
|
||||
label: '通告内容',
|
||||
component: 'Input',
|
||||
colProps: { span: 24 },
|
||||
ifShow: ({}) => _formData.disabled !== false,
|
||||
slot: 'msgContent',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@ -184,10 +184,6 @@
|
||||
confirm: handleDelete.bind(null, record),
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '首页配置',
|
||||
onClick: handleIndexConfig.bind(null, record.roleCode),
|
||||
},
|
||||
];
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="registerModal" :width="800" title="用户代理" @ok="handleSubmit" destroyOnClose>
|
||||
<BasicForm @register="registerForm" />
|
||||
<template #insertFooter>
|
||||
<Popconfirm title="确定删除当前配置的代理吗?" @confirm="handleDel">
|
||||
<a-button v-if="agentData.id"><Icon icon="ant-design:clear-outlined" />删除代理</a-button>
|
||||
</Popconfirm>
|
||||
</template>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
@ -8,7 +13,8 @@
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, useForm } from '/@/components/Form/index';
|
||||
import { formAgentSchema } from './user.data';
|
||||
import { getUserAgent, saveOrUpdateAgent } from './user.api';
|
||||
import { deleteAgent, getUserAgent, saveOrUpdateAgent } from './user.api';
|
||||
import { Popconfirm } from 'ant-design-vue';
|
||||
// 声明Emits
|
||||
const emit = defineEmits(['success', 'register']);
|
||||
//表单配置
|
||||
@ -16,6 +22,8 @@
|
||||
schemas: formAgentSchema,
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
//表单数据
|
||||
const agentData = ref<any>({});
|
||||
//表单赋值
|
||||
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
|
||||
//重置表单
|
||||
@ -24,6 +32,8 @@
|
||||
//查询获取表单数据
|
||||
const res = await getUserAgent({ userName: data.userName });
|
||||
data = res.result ? res.result : data;
|
||||
//代理数据赋值
|
||||
agentData.value = { ...data };
|
||||
//表单赋值
|
||||
await setFieldsValue({ ...data });
|
||||
});
|
||||
@ -42,4 +52,20 @@
|
||||
setModalProps({ confirmLoading: false });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除代理
|
||||
*/
|
||||
async function handleDel() {
|
||||
const reload = async () => {
|
||||
await resetFields();
|
||||
await setFieldsValue({ userName: agentData.value.userName });
|
||||
//关闭弹窗
|
||||
closeModal();
|
||||
emit('success');
|
||||
};
|
||||
if (agentData.value.id) {
|
||||
await deleteAgent({ id: agentData.value.id }, reload);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -8,6 +8,7 @@ enum Api {
|
||||
edit = '/sys/user/edit',
|
||||
agentSave = '/sys/sysUserAgent/add',
|
||||
agentEdit = '/sys/sysUserAgent/edit',
|
||||
deleteAgent = '/sys/sysUserAgent/delete',
|
||||
getUserRole = '/sys/user/queryUserRole',
|
||||
duplicateCheck = '/sys/duplicate/check',
|
||||
deleteUser = '/sys/user/delete',
|
||||
@ -208,6 +209,15 @@ export const saveOrUpdateAgent = (params) => {
|
||||
let url = params.id ? Api.agentEdit : Api.agentSave;
|
||||
return defHttp.post({ url: url, params });
|
||||
};
|
||||
/**
|
||||
* 代理删除
|
||||
* @param params
|
||||
*/
|
||||
export const deleteAgent = (params, handleSuccess) => {
|
||||
return defHttp.delete({ url: Api.deleteAgent, params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 用户离职(新增代理人和用户状态变更操作)
|
||||
|
||||
Reference in New Issue
Block a user