移除SVN

This commit is contained in:
zjl 2024-12-12 16:14:17 +08:00
parent 77db92365d
commit f2758afb35
1106 changed files with 0 additions and 140693 deletions

View File

@ -1 +0,0 @@
12

View File

@ -1 +0,0 @@
12

View File

@ -1,14 +0,0 @@
import { App } from 'vue';
import { perm,perms } from '@/directives/permission';
import { scrollBar } from '@/directives/scrollBar';
/**
* 注册全局自定义指令
* @param app
*/
export function setupDirectives(app: App) {
app.directive('perm', perm); // 权限控制指令 (是否包含其中某个权限)
app.directive('perms', perms); // 权限控制指令 (是否包含所有权限)
app.directive('scrollBar', scrollBar); // 滚动条
}

View File

@ -1,36 +0,0 @@
import type { FunctionalComponent, defineComponent } from 'vue';
import type { ComponentType } from '../../types/componentType';
import { componentMap } from '@/components/Table/src/componentMap';
import { h } from 'vue';
import { Popover } from 'ant-design-vue';
export interface ComponentProps {
component: ComponentType;
rule: boolean;
popoverVisible: boolean;
ruleMessage: string;
}
export const CellComponent: FunctionalComponent = (
{ component = 'Input', rule = true, ruleMessage, popoverVisible }: ComponentProps,
{ attrs },
) => {
const Comp = componentMap.get(component) as typeof defineComponent;
const DefaultComp = h(Comp, attrs);
if (!rule) {
return DefaultComp;
}
return h(
Popover,
{
overlayClassName: 'edit-cell-rule-popover',
visible: !!popoverVisible,
},
{
default: () => DefaultComp,
content: () => ruleMessage,
},
);
};

View File

@ -1,38 +0,0 @@
.fullscreen-modal {
overflow: hidden;
.ant-modal {
top: 0 !important;
right: 0 !important;
bottom: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100%;
&-content {
height: 100%;
}
}
}
.ant-modal {
width: 520px;
padding-bottom: 0;
&-title {
font-size: 16px;
line-height: 16px;
.base-title {
cursor: move !important;
}
}
&-close-x {
display: inline-block;
width: 96px;
height: 56px;
line-height: 56px;
}
}

View File

@ -1,202 +0,0 @@
<template>
<PageWrapper>
<a-card :bordered="false" class="pt-3 mb-3 proCard">
<BasicForm @register="register" @submit="handleSubmit" @reset="handleReset">
<template #statusSlot="{ model, field }">
<a-input v-model="model[field]" />
</template>
</BasicForm>
</a-card>
<a-card :bordered="false" class="proCard">
<BasicTable
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
ref="tableRef"
scroll-x="1200"
:row-selection="{ onChange: onSelectionChange }"
virtual-scroll
>
<template #tableTitle>
<a-space>
<a-button type="primary" @click="handleAdd" v-perm="['sys:ad:add']">
<template #icon>
<PlusOutlined />
</template>
新建
</a-button>
<a-button
type="danger"
@click="handleDelete()"
:disabled="!selectionData.length"
v-perm="['sys:ad:batchDelete']"
>
<template #icon>
<DeleteOutlined />
</template>
删除
</a-button>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<a-space>
<a-button type="primary" @click="handleEdit(record.id)" v-perm="['sys:ad:update']">
<template #icon><EditOutlined /></template>
编辑
</a-button>
<a-button
type="primary"
danger
@click="handleDelete(record.id)"
v-perm="['sys:ad:delete']"
>
<template #icon><DeleteOutlined /></template>
删除
</a-button>
</a-space>
</template>
</template>
</BasicTable>
</a-card>
<editDialog
v-if="editVisible"
:adId="adId"
v-model:visible="editVisible"
@success="reloadTable('noRefresh')"
/>
</PageWrapper>
</template>
<script lang="ts" setup>
import { h, nextTick, reactive, ref, defineAsyncComponent } from 'vue';
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue';
import { useForm } from '@/components/Form/index';
import { getAdList, adDelete, adBatchDelete } from '@/api/content/ad';
import { columns } from './columns';
import { schemas } from './querySchemas';
import { Modal, message } from 'ant-design-vue';
/**
* 定义参数变量
*/
const adId = ref(0);
const tableRef = ref();
const editVisible = ref(false);
const selectionData = ref([]);
/**
* 导入组件
*/
const editDialog = defineAsyncComponent(() => import('./edit.vue'));
/**
* 定义查询参数
*/
const formParams = reactive({
title: '',
status: '',
adSortId: '',
});
/**
* 加载数据列表
* @param res 参数
*/
const loadDataTable = async (res) => {
const result = await getAdList({ ...formParams, ...res });
return result;
};
/**
* 刷新数据列表
* @param noRefresh 参数
*/
function reloadTable(noRefresh = '') {
tableRef.value.reload(noRefresh ? {} : { pageNo: 1 });
}
/**
* 执行编辑
* @param id 参数
*/
async function handleEdit(id) {
adId.value = id;
await nextTick();
editVisible.value = true;
}
/**
* 执行删除
* @param id 参数
*/
async function handleDelete(id) {
Modal.confirm({
title: '提示',
content: '确定要删除?',
onOk: async () => {
id ? await adDelete(id) : await adSortBatchDelete(selectionData.value);
message.success('删除成功');
reloadTable();
},
});
}
/**
* 执行提交表单
* @param values 参数
*/
function handleSubmit(values) {
for (const key in formParams) {
formParams[key] = '';
}
for (const key in values) {
formParams[key] = values[key];
}
reloadTable();
}
/**
* 执行重置
*/
function handleReset() {
for (const key in formParams) {
formParams[key] = '';
}
reloadTable();
}
/**
* 选项发生变化
* @param value 参数
*/
function onSelectionChange(value) {
selectionData.value = value;
}
/**
* 注册
*/
const [register, {}] = useForm({
rowProps: { gutter: [16, 0] },
colProps: {
xs: 24,
sm: 24,
md: 12,
lg: 8,
xl: 6,
},
labelCol: { span: 6, offset: 0 },
schemas,
});
/**
* 执行添加
*/
const handleAdd = async () => {
adId.value = 0;
await nextTick();
editVisible.value = true;
};
</script>

View File

@ -1,76 +0,0 @@
import { h } from 'vue';
import { Tag } from 'ant-design-vue';
export const columns = [
{
title: 'ID',
dataIndex: 'id',
width: 100,
},
{
title: '参数名称',
dataIndex: 'name',
},
{
title: '参数编码',
dataIndex: 'code',
},
{
title: '参数值',
dataIndex: 'value',
},
{
title: '参数类型',
dataIndex: 'type',
customRender({ record }) {
return h(
Tag,
{
color: record.type ==0 ? 'processing' : 'warning',
},
{
default: () => (record.type ==0 ? '系统' : '业务'),
},
);
},
},
{
title: '参数状态',
dataIndex: 'status',
customRender({ record }) {
return h(
Tag,
{
color: record.status ==1 ? 'success' : 'error',
},
{
default: () => (record.status ==1 ? '正常' : '禁用'),
},
);
},
},
{
title: '排序',
dataIndex: 'sort',
},
{
title: '备注',
dataIndex: 'note',
},
{
title: '创建人',
dataIndex: 'createUser',
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 180,
},
{
title: '操作',
fixed:'right',
dataIndex: 'action',
key: 'action',
width: 200,
},
];

View File

@ -1,31 +0,0 @@
import { defineStore } from 'pinia';
import { IS_LOCKSCREEN } from '@/store/mutation-types';
import { storage } from '@/utils/Storage';
// 长时间不操作默认锁屏时间
const initTime = 60 * 60;
const isLock = storage.get(IS_LOCKSCREEN, false);
export type ILockscreenState = {
isLock: boolean; // 是否锁屏
lockTime: number;
};
export const useLockscreenStore = defineStore({
id: 'app-lockscreen',
state: (): ILockscreenState => ({
isLock: isLock === true, // 是否锁屏
lockTime: isLock == 'true' ? initTime : 0,
}),
getters: {},
actions: {
setLock(payload) {
this.isLock = payload;
storage.set(IS_LOCKSCREEN, this.isLock);
},
setLockTime(payload = initTime) {
this.lockTime = payload;
},
},
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -1,92 +0,0 @@
import { computed, onMounted, reactive, toRefs } from 'vue';
interface Battery {
charging: boolean; // 当前电池是否正在充电
chargingTime: number; // 距离充电完毕还需多少秒如果为0则充电完毕
dischargingTime: number; // 代表距离电池耗电至空且挂起需要多少秒
level: number; // 代表电量的放大等级,这个值在 0.0 至 1.0 之间
[key: string]: any;
}
export const useBattery = () => {
const state = reactive({
battery: {
charging: false,
chargingTime: 0,
dischargingTime: 0,
level: 100,
},
});
// 更新电池使用状态
const updateBattery = (target) => {
for (const key in state.battery) {
state.battery[key] = target[key];
}
state.battery.level = state.battery.level * 100;
};
// 计算电池剩余可用时间
const calcDischargingTime = computed(() => {
const hour = state.battery.dischargingTime / 3600;
const minute = (state.battery.dischargingTime / 60) % 60;
return `${~~hour}小时${~~minute}分钟`;
});
// 计算电池充满剩余时间
const calcChargingTime = computed(() => {
const hour = state.battery.chargingTime / 3600;
const minute = (state.battery.chargingTime / 60) % 60;
return `${~~hour}小时${~~minute}分钟`;
});
// 电池状态
const batteryStatus = computed(() => {
if (state.battery.charging && state.battery.level >= 100) {
return '已充满';
} else if (state.battery.charging) {
return '充电中';
} else {
return '已断开电源';
}
});
onMounted(async () => {
const BatteryManager: Battery = await (window.navigator as any).getBattery();
updateBattery(BatteryManager);
// 电池充电状态更新时被调用
BatteryManager.onchargingchange = ({ target }) => {
updateBattery(target);
};
// 电池充电时间更新时被调用
BatteryManager.onchargingtimechange = ({ target }) => {
updateBattery(target);
};
// 电池断开充电时间更新时被调用
BatteryManager.ondischargingtimechange = ({ target }) => {
updateBattery(target);
};
// 电池电量更新时被调用
BatteryManager.onlevelchange = ({ target }) => {
updateBattery(target);
};
// new Intl.DateTimeFormat('zh', {
// year: 'numeric',
// month: '2-digit',
// day: '2-digit',
// hour: '2-digit',
// minute: '2-digit',
// second: '2-digit',
// hour12: false
// }).format(new Date())
});
return {
...toRefs(state),
batteryStatus,
calcDischargingTime,
calcChargingTime,
};
};

View File

@ -1,46 +0,0 @@
<template>
<a-card :bordered="false" class="proCard">
<div class="result-box">
<a-result
status="success"
title="操作成功"
description="提交结果页用于反馈一系列操作任务的处理结果,如果仅是简单操作,灰色区域可以显示一些补充的信息。"
>
<div class="result-box-extra">
<p>已提交申请,等待财务部门审核。</p>
</div>
<template #extra>
<a-space align="center" class="mb-4">
<a-button type="primary" @click="goHome">回到首页</a-button>
<a-button>查看详情</a-button>
<a-button>打印</a-button>
</a-space>
</template>
</a-result>
</div>
</a-card>
</template>
<script lang="ts" setup>
import { useRouter } from 'vue-router';
const router = useRouter();
function goHome() {
router.push('/');
}
</script>
<style lang="less" scoped>
.result-box {
width: 72%;
margin: 0 auto;
text-align: center;
padding-top: 5px;
&-extra {
padding: 0px 40px;
background: var(--border-color);
border-radius: 4px;
text-align: center;
}
}
</style>

View File

@ -1,152 +0,0 @@
<template>
<a-modal
v-model:visible="props.visible"
:title="props.adSortId ? '编辑' : '新增'"
width="500px"
@cancel="dialogClose"
>
<a-form
class="ls-form"
ref="formRef"
:model="formData"
:label-col="{ style: { width: '100px' } }"
>
<a-form-item
label="广告位名称"
name="name"
:rules="{ required: true, message: '请输入广告位名称', trigger: 'blur' }"
>
<a-input v-model:value="formData.name" placeholder="请输入广告位名称" />
</a-form-item>
<a-form-item
label="页面位置"
name="location"
class="flex-1"
:rules="{ required: true, message: '请输入页面位置', trigger: 'blur' }"
>
<number-input v-model:value="formData.location" placeholder="请输入页面位置" />
</a-form-item>
<a-form-item
label="广告位类型"
name="type"
:rules="{ required: true, message: '请选择广告位类型', trigger: 'change' }"
>
<a-select v-model:value="formData.type" placeholder="请选择广告位类型">
<a-select-option :value="1">网站</a-select-option>
<a-select-option :value="2">手机站</a-select-option>
<a-select-option :value="3">移动端</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="排序" name="sort">
<a-input-number v-model:value="formData.sort" :max="9999" placeholder="请输入排序" />
</a-form-item>
<a-form-item
label="备注"
name="note"
:rules="{ required: true, message: '请输入备注', trigger: 'blur' }"
>
<a-textarea v-model:value="formData.note" placeholder="请输入备注" />
</a-form-item>
</a-form>
<template #footer>
<span class="dialog-footer">
<a-button @click="dialogClose">取消</a-button>
<a-button :loading="subLoading" type="primary" @click="submit"> 确定 </a-button>
</span>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'ant-design-vue';
import { getAdSortDetail, adSortAdd, adSortUpdate } from '@/api/content/adSort';
import { getLayoutAllList } from '@/api/content/layout';
import { onMounted, reactive, shallowRef, ref } from 'vue';
import { message } from 'ant-design-vue';
import { useLockFn } from '@/utils/useLockFn';
/**
* 定义参数变量
*/
const emit = defineEmits(['success', 'update:visible']);
const formRef = shallowRef<FormInstance>();
/**
* 定义表单参数
*/
const formData = reactive({
id: '',
name: '',
location: '',
note: '',
type: undefined,
sort: 0,
});
/**
* 定义接收的参数
*/
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
adSortId: {
type: Number,
required: true,
default: 0,
},
});
const locationList = ref([]);
/**
* 执行提交表单
*/
const handleSubmit = async () => {
await formRef.value?.validate();
props.adSortId ? await adSortUpdate(formData) : await adSortAdd(formData);
message.success('操作成功');
emit('update:visible', false);
emit('success');
};
/**
* 关闭窗体
*/
const dialogClose = () => {
emit('update:visible', false);
};
const { isLock: subLoading, lockFn: submit } = useLockFn(handleSubmit);
/**
* 设置表单数据
*/
const setFormData = async () => {
const data = await getAdSortDetail(props.adSortId);
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key];
}
}
};
/**
* 获取全部字典数据
*/
const getAllDict = async () => {
let list = await getLayoutAllList();
locationList.value = list ? list : [];
};
/**
* 钩子函数
*/
onMounted(() => {
getAllDict();
if (props.adSortId) {
setFormData();
}
});
</script>

View File

@ -1,194 +0,0 @@
<template>
<div class="menu-index">
<a-card :bordered="false" class="pt-3 mb-3 proCard">
<div>
<a-space>
<a-button type="primary" @click="handleAdd()" v-perm="['sys:dept:add']">
<template #icon><PlusOutlined /></template>
新增
</a-button>
<a-button @click="handleExpand"> 展开/折叠</a-button>
</a-space>
</div>
</a-card>
<a-card :bordered="false" class="pt-3 mb-3 proCard">
<a-spin :spinning="loading">
<a-table
border
ref="tableRef"
:dataSource="lists"
:columns="columns"
v-model:expandedRowKeys="expandKeys"
:style="{ minHeight: fwbHeight+'px' }"
:scroll="{x:'100%',y:fwbHeight}"
>
<template #bodyCell="{ column, record, index }">
<template v-if="column.key == 'action'">
<a-space>
<a-button
type="primary"
@click="handleAdd(record.id)"
v-perm="['sys:category:add']"
>
<template #icon><PlusOutlined /></template>
新增</a-button
>
<a-button
type="primary"
@click="handleEdit(record)"
v-perm="['sys:category:update']"
>
<template #icon><EditOutlined /></template>
编辑
</a-button>
<a-button
type="primary"
danger
@click="handleDelete(record.id)"
v-perm="['sys:category:delete']"
>
<template #icon><DeleteOutlined /></template>
删除
</a-button>
</a-space>
</template>
</template>
</a-table>
</a-spin>
</a-card>
<editDialog
ref="editRef"
v-if="editVisible"
:categoryId="categoryId"
:pid="pid"
v-model:visible="editVisible"
@success="getLists"
/>
</div>
</template>
<script lang="ts" setup name="menu">
import { defineAsyncComponent, nextTick, onMounted, ref } from 'vue';
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue';
import { getCategoryList, categoryDelete } from '@/api/content/category';
import { Modal, message } from 'ant-design-vue';
import { columns } from './columns';
import { buildTree } from '@/utils/auth';
/**
* 导入组件
*/
const editDialog = defineAsyncComponent(() => import('./edit.vue'));
/**
* 定义参数变量
*/
const fwbHeight = document.body.clientHeight - 400;
const loading = ref(false);
const editVisible = ref(false);
const expandAllRows = ref(false);
const arrayList = ref([]);
const expandKeys = ref([]);
const categoryId = ref(0);
const pid = ref(0);
const lists = ref([]);
/**
* 获取分类数据
*/
const getLists = async () => {
loading.value = true;
try {
const data = await getCategoryList();
data.map((item) => {
item.key = item.id;
});
arrayList.value = data;
lists.value = buildTree(data);
loading.value = false;
} catch (error) {
loading.value = false;
}
};
/**
* 执行添加
* @param parentId 上级ID
*/
const handleAdd = async (parentId: any) => {
categoryId.value = 0;
pid.value = parentId ? parentId : 0;
await nextTick();
editVisible.value = true;
};
/**
* 执行编辑
* @param data 参数
*/
const handleEdit = async (data: any) => {
categoryId.value = data.id;
await nextTick();
editVisible.value = true;
};
/**
* 执行删除
* @param categoryId 分类ID
*/
const handleDelete = (categoryId: number) => {
Modal.confirm({
title: '提示',
content: '确定要删除?',
onOk: async () => {
loading.value = true;
await categoryDelete(categoryId);
message.success('删除成功');
getLists();
loading.value = false;
},
});
};
/**
* 执行扩展、收缩
*/
const handleExpand = () => {
expandAllRows.value = !expandAllRows.value;
toggleExpand();
};
/**
* 扩展、收缩实现
*/
const toggleExpand = () => {
expandKeys.value = [];
if (expandAllRows.value) {
arrayList.value.map((item) => {
expandKeys.value.push(item.id);
});
} else {
expandKeys.value = [];
}
};
/**
* 获取全部数据
*/
const getAll = () => {
getLists();
};
/**
* 钩子函数
*/
onMounted(() => {
getAll();
});
// onActivated(() => {
// getAll()
// });
</script>
<style scoped></style>

View File

@ -1,63 +0,0 @@
export const basicProps = {
//密码框内容
value: {
type: [Number, String],
default: '',
},
//是否必填
required: {
type: Boolean,
default: true,
},
//是否为复杂密码
// 数字、字母和字符两种或以上组合
complexity: {
type: Boolean,
default: true,
},
complexityTip: {
type: String,
default: '需包含字母、数字及特殊字符两种或以上组合',
},
//密码最短长度要求
minLength: {
type: Number,
default: 6,
},
//密码最大长度要求
maxLength: {
type: Number,
default: 32,
},
//密码等级提示语
// 自定义时 1 - 4 级需要对应
level: {
type: Object,
default: {
1: '弱不禁风',
2: '平淡无奇',
3: '出神入化',
4: '登峰造极',
},
},
//验证规格
rules: {
type: Object,
default: () => {},
},
//是否显示 [ 再次确认密码 ] 输入框
repeat: {
type: Boolean,
default: false,
},
//尺寸
size: {
type: String,
default: 'medium',
},
//block属性将使按钮适合其父宽度
block: {
type: Boolean,
default: false,
},
};

View File

@ -1,41 +0,0 @@
<template>
<PageWrapper>
<a-card shadow="never" size="small" class="proCard tabsCard">
<a-tabs v-model="activeName">
<a-tab-pane name="basic" label="基本设置">
<BasicSetting />
</a-tab-pane>
</a-tabs>
</a-card>
</PageWrapper>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { PageWrapper } from '@/components/Page';
import BasicSetting from './BasicSetting.vue';
const activeName = ref('basic');
</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>

View File

@ -1,60 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 列表
*/
export function getEmailTemplateList(params?) {
return http.request({
url: '/email/template/page',
method: 'GET',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getEmailTemplateDetail(id) {
return http.request({
url: '/email/template/detail/' + id,
method: 'get',
});
}
/**
* @description: 添加
*/
export function emailTemplateAdd(data: any) {
return http.request({
url: '/email/template/add',
method: 'POST',
data,
});
}
/**
* @description: 更新
*/
export function emailTemplateUpdate(data: any) {
return http.request({
url: '/email/template/update',
method: 'PUT',
data,
});
}
/**
* @description: 删除
*/
export function emailTemplateDelete(id) {
return http.request({
url: '/email/template/delete/' + id,
method: 'DELETE',
});
}
/**
* @description: 批量删除
*/
export function emailTemplateBatchDelete(data: any) {
return http.request({
url: '/email/template/batchDelete',
method: 'DELETE',
data,
});
}

View File

@ -1,233 +0,0 @@
<template>
<div class="account">
<div class="account-container">
<div class="account-wrap-login">
<div class="login-pic">
<h1 class="login-title">WMS </h1>
<h4 class="login-subtitle">界面美观组件丰富的中后台前端解决方案 </h4>
</div>
<div class="login-form">
<div class="login-form-container">
<div class="account-top">
<div class="account-top-desc">{{loginFlag?'用户登录':'用户注册'}}</div>
</div>
<template v-if="loginFlag">
<div class="account-tab-box">
<div :class="activeIndex==index?'active':''" v-for="(item,index) in tabData" @click="handleClick(index)" :key="index">{{item}}</div>
</div>
<LoginForm v-if="activeIndex === 0" @backLogin="goLogin"/>
<PhoneForm v-else-if="activeIndex === 1"/>
<QrcodeForm v-else-if="activeIndex === 2"></QrcodeForm>
</template>
<template v-else>
<RegisterForm @backLogin="goLogin"></RegisterForm>
</template>
</div>
<div class="corner-box" @click="handleCornerClick">
<UserAddOutlined v-if="loginFlag" style="color: #FFFFFF; font-size: 30px"/>
<RollbackOutlined v-else style="color: #FFFFFF; font-size: 30px"/>
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import LoginForm from './LoginForm2.vue';
import PhoneForm from './PhoneForm.vue';
import QrcodeForm from './QrcodeForm.vue';
import RegisterForm from './RegisterForm2.vue';
import {
UserAddOutlined,
RollbackOutlined
} from '@ant-design/icons-vue';
const loginFlag = ref(true)
const activeIndex = ref(0)
const tabData =ref(['账号登录','手机号登录','扫码登录'])
const handleClick =(index)=>{
activeIndex.value = index
}
const handleCornerClick = ()=>{
loginFlag.value = !loginFlag.value
}
const goLogin = (type)=>{
loginFlag.value = type
}
</script>
<style lang="less" scoped>
.account {
width: 100%;
margin: 0 auto;
&-container {
width: 100%;
min-height: 100vh;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
padding: 20px;
box-sizing: border-box;
background-image:url('@/assets/images/login-bg.png');
background-repeat: no-repeat;
background-size: 100% 100%;
}
&-wrap-login {
width: 920px;
height: 510px;
background: #fff;
border-radius: 10px;
overflow: hidden;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.login-pic {
flex: 1;
padding: 32px 8px;
box-sizing: border-box;
background-color: #1681fd;
background-image: url('@/assets/images/login-img.png');
background-repeat: no-repeat;
background-position: bottom;
background-size: contain;
text-align: center;
.login-title {
color: #ffffff;
font-size: 28px;
margin: 0 0 6px;
font-weight: 400;
letter-spacing: 1.2px;
}
.login-subtitle {
color: #fffc;
font-size: 16px;
margin: 0;
font-weight: 400;
letter-spacing: 4px;
letter-spacing: 1.2px;
}
}
img {
max-width: 100%;
}
.login-form {
width: 400px;
position: relative;
&-container {
margin: auto;
width: 100%;
padding:32px 48px 0;
box-sizing: border-box;
}
&-title {
padding-bottom: 15px;
text-align: center;
}
.corner-box {
position:absolute;
top:0;
right:0;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
right: 0;
top: 0;
width: 80px;
height: 80px;
border-radius: 0 0 0 150%;
background: #1890ff;
cursor: pointer;
>i {
margin-right: -20px;
margin-top: -10px;
}
}
}
@media (max-width: 680px) {
.login-pic {
padding: 20px 12px 100px;
background-size: auto 100px;
}
.login-form {
width: 100%;
margin: auto;
}
}
.account-top {
&-desc {
font-size: 24px;
font-weight: bold;
color: #000000;
margin-bottom: 18px;
}
}
.account-tab-box {
display: flex;
height:34px;
margin-bottom: 18px;
background-color: #f5f5f5;
border-radius: 4px;
padding:3px;
>div {
flex:1;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
color:rgba(0, 0, 0, .6);
&.active {
background-color:#ffffff;
color:rgba(0, 0, 0, .92);
}
&:hover {
color:rgba(0, 0, 0, .92);
}
}
}
}
@media (max-width: 680px) {
&-container {
padding: 0;
display: block;
background: #fff;
}
&-wrap-login {
display: block;
height: auto;
width: 100%;
background: none;
box-shadow: none;
border-radius: 0;
}
}
}
</style>
<style lang="less">
// .account {
// .el-button--primary {
// background-color:blue
// }
// .el-button--text{
// padding:0;
// }
// .el-checkbox__input.is-checked+.el-checkbox__label,.el-button--text {
// color: blue;
// }
// .el-checkbox__input.is-checked .el-checkbox__inner {
// background-color: blue;
// color: blue;
// }
// }
</style>

View File

@ -1,60 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 列表
*/
export function getMessageTemplateList(params?) {
return http.request({
url: '/message/template/page',
method: 'GET',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getMessageTemplateDetail(id) {
return http.request({
url: '/message/template/detail/'+id,
method: 'get',
});
}
/**
* @description: 添加
*/
export function messageTemplateAdd(data:any) {
return http.request({
url: '/message/template/add',
method: 'POST',
data,
});
}
/**
* @description: 更新
*/
export function messageTemplateUpdate(data:any) {
return http.request({
url: '/message/template/update',
method: 'PUT',
data
});
}
/**
* @description: 删除
*/
export function messageTemplateDelete(id) {
return http.request({
url: '/message/template/delete/'+id,
method: 'DELETE',
});
}
/**
* @description: 批量删除
*/
export function messageTemplateBatchDelete(data:any) {
return http.request({
url: '/message/template/batchDelete',
method: 'DELETE',
data
});
}

View File

@ -1,34 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 列表
*/
export function getTableList(params?) {
return http.request({
url: '/admin/generator/page',
method: 'GET',
params,
});
}
/**
* @description: 一键生成
*/
export function generator(data: any) {
return http.request({
url: '/admin/generator/generator',
method: 'POST',
data,
});
}
/**
* @description: 批量删除
*/
export function batchGenerator(data: any) {
return http.request({
url: '/admin/generator/batchGenerate',
method: 'POST',
data,
});
}

View File

@ -1,214 +0,0 @@
<template>
<a-modal v-model:visible="props.visible" :title="props.tenantId ? '编辑' : '新增'" :width="800"
style="top:20px;" @cancel="dialogClose">
<a-form ref="formRef" :model="formData" :label-col="{ style: { width: '140px' }}">
<div class="flex">
<a-form-item
label="租户图片"
name="image"
:rules="{ required: true,message: '请上传租户图片', trigger: 'change' }"
>
<UploadImg @changeFileName="(name)=>formData.imageImgName=name"
:fileType=" ['image/jpeg', 'image/png', 'image/jpg', 'image/gif']"
name="tenant"
:fileSize="200"
v-model:image-url="formData.image" :cropper="false">
<template v-slot:tip>支持扩展名: jpg png jpeg;文件大小不超过200M</template>
</UploadImg>
</a-form-item>
</div>
<div class="flex">
<a-form-item label="名称" name="name" class="flex-1"
:rules="{ required: true, message: '请输入名称', trigger: 'blur' }">
<a-input v-model:value="formData.name" placeholder="请输入名称" allow-clear />
</a-form-item>
<a-form-item label="编号" name="code" class="flex-1"
:rules="{ required: true, message: '请输入编号', trigger: 'blur' }">
<a-input v-model:value="formData.code" allow-clear
placeholder="请输入编号" />
</a-form-item>
</div>
<div class="flex">
<a-form-item label="统一社会信用代码" name="license" class="flex-1"
:rules="{ required: true, message: '请输入统一社会信用代码', trigger: 'blur' }">
<a-input v-model:value="formData.license" placeholder="请输入统一社会信用代码" allow-clear />
</a-form-item>
<a-form-item label="联系人" name="contactUser" class="flex-1"
:rules="{ required: true, message: '请输入联系人', trigger: 'blur' }">
<a-input v-model:value="formData.contactUser" placeholder="请输入联系人" allow-clear />
</a-form-item>
</div>
<div class="flex">
<a-form-item label="联系电话" name="contactMobile" class="flex-1"
:rules="{ required: true, message: '请输入联系电话', trigger: 'blur' }">
<a-input v-model:value="formData.contactMobile" placeholder="请输入联系电话" allow-clear />
</a-form-item>
<a-form-item label="邮箱地址" name="contactEmail" class="flex-1"
:rules="[{ required: true, message: '请输入邮箱地址', trigger: 'blur' },{ type: 'email', message: '请输入正确邮箱地址', trigger: 'blur'}]">
<a-input v-model:value="formData.contactEmail" placeholder="请输入邮箱地址" allow-clear />
</a-form-item>
</div>
<div class="flex">
<a-form-item label="官网地址" name="contactSite" class="flex-1"
:rules="{ required: true, message: '请输入官网地址', trigger: 'blur'}">
<a-input v-model:value="formData.contactSite" placeholder="请输入官网地址" allow-clear />
</a-form-item>
<a-form-item label="用户限额" name="number" class="flex-1"
:rules="{ required: true, message: '请输入用户限额', trigger: 'blur'}">
<number-input v-model="formData.number" placeholder="请输入用户限额" allow-clear />
</a-form-item>
</div>
<div class="flex">
<a-form-item label="过期时间" name="expireTime" class="flex-1"
:rules="{ required: true, message: '请选择过期时间', trigger: 'change'}">
<a-date-picker show-time placeholder="请选择过期时间" v-model:value="formData.expireTime" format="YYYY-MM-DD HH:mm:ss" valueFormat="YYYY-MM-DD HH:mm:ss"/>
</a-form-item>
<a-form-item label="租户地址" name="contactAddress" class="flex-1"
:rules="{ required: true, message: '请输入租户地址', trigger: 'blur'}">
<a-input v-model:value="formData.contactAddress" placeholder="请输入租户地址" allow-clear />
</a-form-item>
</div>
<div class="flex">
<a-form-item label="简介" name="contactIntro" class="flex-1"
:rules="{ required: true, message: '请输入简介', trigger: 'blur'}">
<a-input v-model:value="formData.contactIntro" type="textarea" placeholder="请输入简介" allow-clear />
</a-form-item>
</div>
<div class="flex">
<a-form-item label="备注" name="contactNote" class="flex-1">
<a-input v-model:value="formData.contactNote" type="textarea" placeholder="请输入备注" allow-clear />
</a-form-item>
</div>
<div class="flex">
<a-form-item label="租户状态" name="status" class="flex-1">
<a-radio-group v-model:value="formData.status" name="status">
<a-radio :value="0">正常</a-radio>
<a-radio :value="1">禁用</a-radio>
</a-radio-group>
</a-form-item>
</div>
</a-form>
<template #footer>
<span class="dialog-footer">
<a-button @click="dialogClose">取消</a-button>
<a-button :loading="subLoading" type="primary" @click="submit">
确定
</a-button>
</span>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import { getTenantDetail, tenantAdd, tenantUpdate } from '@/api/system/tenant';
import { onMounted, reactive, shallowRef } from "vue";
import { getRoleAllList } from '@/api/system/role';
import { getDeptList } from '@/api/system/dept';
import { getLevelAllList } from '@/api/system/level';
import { getPositionAllList } from '@/api/system/position';
import UploadImg from "@/components/Upload/Image.vue";
import {buildTree } from "@/utils/auth";
import type { FormInstance } from 'ant-design-vue';
const formRef = shallowRef<FormInstance>();
import { useLockFn } from "@/utils/useLockFn";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false
},
tenantId: {
type: Number,
required: true,
default: 0
}
});
const emit = defineEmits(["success", "update:visible"]);
const formData = reactive({
id: 0,
code:'',
name: '',
image:'',
license: "",
contactUser: "",
contactMobile: '',
contactEmail: '',
contactAddress:'',
contactIntro: '',
contactSite: '',
contactNote: '',
expireTime: '',
status: 0,
number: ''
});
const passwordConfirmValidator = (
rule: object,
value: string,
callback: any
) => {
if (formData.password) {
if (!value) callback(new Error("请再次输入密码"));
if (value !== formData.password) callback(new Error("两次输入密码不一致!"));
}
callback();
};
const dialogClose = () => {
emit("update:visible", false);
};
const setFormData = async (row: any) => {
const data = await getTenantDetail(row.tenantId);
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
formData[key] = data[key];
}
}
};
const handleSubmit = async () => {
console.log(formData)
await formRef.value?.validate();
props.tenantId ? await tenantUpdate(formData) : await tenantAdd(formData);
emit("update:visible", false);
emit("success");
};
const { isLock: subLoading, lockFn: submit } = useLockFn(handleSubmit);
const optionData = reactive({
roleList: [],
deptList: [],
levelList: [],
positionList: []
});
function uploadChange(data: string[]) {
formData.avatar = data.fileUrl;
formData.avatarName =data.fileName
}
const handleDelete =async(file)=>{
console.log(file)
}
const getAllDict = async () => {
let list = await getRoleAllList();
optionData.roleList = list ? list : [];
list = await getDeptList();
optionData.deptList = list ? buildTree(list) : [];
list = await getLevelAllList();
optionData.levelList = list ? list : [];
list = await getPositionAllList();
optionData.positionList = list ? list : [];
};
onMounted(() => {
getAllDict()
if (props.tenantId) {
setFormData({ tenantId: props.tenantId });
}
});
</script>

View File

@ -1,54 +0,0 @@
<template>
<div class="page-wrapper" :class="{ 'footer-space': showFooter && getShowFooter }">
<div class="mb-4 n-layout-page-header" v-if="title || content || $slots.headerContent">
<a-card :bordered="false" :title="title">
{{ content }}
<slot name="headerContent"></slot>
</a-card>
</div>
<div class="page-wrapper-content" :style="contentStyle" :class="contentClass">
<slot></slot>
</div>
<page-footer v-if="showFooter && getShowFooter" :style="getFooterWidth">
<template #left>
<slot name="leftFooter"></slot>
</template>
<template #right>
<slot name="rightFooter"></slot>
</template>
</page-footer>
</div>
</template>
<script lang="ts" setup>
import { computed, useSlots } from 'vue';
import { basicProps } from './wrapperProps';
import PageFooter from './PageFooter.vue';
import { useProjectSetting } from '@/hooks/setting/useProjectSetting';
const slots = useSlots();
defineProps({ ...basicProps });
const { getMenuCollapsed, getMenuMinWidth, getMenuWidth } = useProjectSetting();
const getShowFooter = computed(() => slots?.leftFooter || slots?.rightFooter);
const getFooterWidth = computed(() => {
const wh = getMenuCollapsed.value ? getMenuMinWidth.value : getMenuWidth.value;
return {
width: `calc(100% - ${wh}px)`,
};
});
</script>
<style lang="less" scoped>
.page-wrapper {
.mb-4 {
margin-bottom: 1rem;
}
}
.footer-space {
padding-bottom: 64px;
}
</style>

View File

@ -1,142 +0,0 @@
<template>
<a-modal
v-model:visible="props.visible"
:title="props.noticeId ? '编辑' : '新增'"
:width="`${size}px`"
@cancel="dialogClose"
style="top: 20px"
>
<a-form
class="ls-form"
ref="formRef"
:model="formData"
:label-col="{ style: { width: '80px' } }"
>
<a-form-item
label="通知标题"
name="title"
:rules="{ required: true, message: '请输入通知标题', trigger: 'blur' }"
>
<a-input class="ls-input" v-model:value="formData.title" placeholder="通知标题" clearable />
</a-form-item>
<a-form-item label="通知类型">
<a-select v-model:value="formData.type" placeholder="请选择通知类型">
<a-select-option :value="1">通知</a-select-option>
<a-select-option :value="2">公告</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="通知状态" name="status">
<a-radio-group v-model:value="formData.status" name="status">
<a-radio :value="1">正常</a-radio>
<a-radio :value="2">关闭</a-radio>
</a-radio-group>
</a-form-item>
<div class="flex">
<a-form-item
class="flex-1"
label="通知内容"
name="content"
:rules="{ required: true, message: '请输入通知内容', trigger: 'blur' }"
>
<Editor ref="editorRef" :height="fwbHeight" class="flex-1" name="data" />
</a-form-item>
</div>
</a-form>
<template #footer>
<span class="dialog-footer">
<a-button @click="dialogClose">取消</a-button>
<a-button :loading="subLoading" type="primary" @click="submit"> 确定 </a-button>
</span>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'element-plus';
import { getNoticeDetail, noticeAdd, noticeUpdate } from '@/api/data/notice';
import { onMounted, reactive, shallowRef, ref } from 'vue';
import Editor from '@/components/Editor/tinymce.vue';
import { message } from 'ant-design-vue';
import { useLockFn } from '@/utils/useLockFn';
/**
* 定义参数变量
*/
const size = document.body.clientWidth - 500;
const emit = defineEmits(['success', 'update:visible']);
const formRef = shallowRef<FormInstance>();
const editorRef = ref();
/**
* 定义表单参数
*/
const formData = reactive({
id: '',
title: '',
status: 1,
type: 1,
content: '',
});
/**
* 定义接收的参数
*/
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
noticeId: {
type: Number,
required: true,
default: 0,
},
});
const fwbHeight = document.body.clientHeight - 400;
/**
* 执行提交表单
*/
const handleSubmit = async () => {
formData.content = editorRef.value.myValue;
await formRef.value?.validate();
let ruleForm = JSON.parse(JSON.stringify(formData));
ruleForm.content = editorRef.value.myValue;
props.noticeId ? await noticeUpdate(ruleForm) : await noticeAdd(ruleForm);
message.success('操作成功');
emit('update:visible', false);
emit('success');
};
/**
* 关闭窗体
*/
const dialogClose = () => {
emit('update:visible', false);
};
const { isLock: subLoading, lockFn: submit } = useLockFn(handleSubmit);
/**
* 设置表单数据
*/
const setFormData = async () => {
const data = await getNoticeDetail(props.noticeId);
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key];
}
}
editorRef.value.myValue = formData.content;
};
/**
* 钩子函数
*/
onMounted(() => {
if (props.noticeId) {
setFormData();
}
});
</script>

View File

@ -1,108 +0,0 @@
<template>
<div ref="chartRef" :style="{ height, width }"></div>
</template>
<script lang="ts" setup>
import { onMounted, ref, Ref } from 'vue';
import { useECharts } from '@/hooks/web/useECharts';
import { basicProps } from './props';
defineProps({
...basicProps,
});
const chartRef = ref<HTMLDivElement | null>(null);
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
onMounted(() => {
setOptions({
tooltip: {
trigger: 'axis',
axisPointer: {
lineStyle: {
width: 1,
color: '#019680',
},
},
},
xAxis: {
type: 'category',
boundaryGap: false,
data: [
'6:00',
'7:00',
'8:00',
'9:00',
'10:00',
'11:00',
'12:00',
'13:00',
'14:00',
'15:00',
'16:00',
'17:00',
'18:00',
'19:00',
'20:00',
'21:00',
'22:00',
'23:00',
],
splitLine: {
show: true,
lineStyle: {
width: 1,
type: 'solid',
color: 'rgba(226,226,226,0.5)',
},
},
axisTick: {
show: false,
},
},
yAxis: [
{
type: 'value',
max: 80000,
splitNumber: 4,
axisTick: {
show: false,
},
splitArea: {
show: true,
areaStyle: {
color: ['rgba(255,255,255,0.2)', 'rgba(226,226,226,0.2)'],
},
},
},
],
grid: { left: '1%', right: '1%', top: '2 %', bottom: 0, containLabel: true },
series: [
{
smooth: true,
data: [
111, 222, 4000, 18000, 33333, 55555, 66666, 33333, 14000, 36000, 66666, 44444, 22222,
11111, 4000, 2000, 500, 333, 222, 111,
],
type: 'line',
areaStyle: {},
itemStyle: {
color: '#5ab1ef',
},
},
{
smooth: true,
data: [
33, 66, 88, 333, 3333, 5000, 18000, 3000, 1200, 13000, 22000, 11000, 2221, 1201, 390,
198, 60, 30, 22, 11,
],
type: 'line',
areaStyle: {},
itemStyle: {
color: '#019680',
},
},
],
});
});
</script>

View File

@ -1,60 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 列表
*/
export function getArticleList(params?) {
return http.request({
url: '/article/page',
method: 'GET',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getArticleDetail(articleId) {
return http.request({
url: '/article/detail/'+articleId,
method: 'get',
});
}
/**
* @description: 添加
*/
export function articleAdd(data:any) {
return http.request({
url: '/article/add',
method: 'POST',
data,
});
}
/**
* @description: 更新
*/
export function articleUpdate(data:any) {
return http.request({
url: '/article/update',
method: 'PUT',
data
});
}
/**
* @description: 删除
*/
export function articleDelete(articleId) {
return http.request({
url: '/article/delete/'+articleId,
method: 'DELETE',
});
}
/**
* @description: 批量删除
*/
export function articleBatchDelete(data:any) {
return http.request({
url: '/article/batchDelete',
method: 'DELETE',
data
});
}

View File

@ -1,307 +0,0 @@
<template>
<PageWrapper>
<a-card :bordered="false" class="pt-3 mb-3 proCard">
<BasicForm @register="register" @submit="handleSubmit" @reset="handleReset" />
</a-card>
<a-card :bordered="false" class="proCard">
<BasicTable
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
ref="tableRef"
:row-selection="{ onChange: onSelectionChange }"
>
<template #tableTitle>
<a-space>
<a-button type="primary" @click="handleAdd" v-perm="['sys:job:add']">
<template #icon>
<PlusOutlined />
</template>
添加任务
</a-button>
<a-button
type="danger"
@click="handleDelete()"
:disabled="!selectionData.length"
v-perm="['sys:job:batchDelete']"
>
<template #icon>
<DeleteOutlined />
</template>
删除
</a-button>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'status'">
<a-switch v-model:checked="record.realStatus" @change="handelSetStatus(record)" />
</template>
<template v-else-if="column.key === 'action'">
<a-space>
<a-button
type="primary"
@click="handelChangeStatus(record)"
v-perm="['sys:job:resume']"
v-if="record.status == 0 || record.status == 2"
>
<template #icon><FieldTimeOutlined /></template>
启动
</a-button>
<a-button
type="primary"
@click="handelChangeStatus(record)"
v-perm="['sys:job:pause']"
v-if="record.status == 1"
>
<template #icon><FieldTimeOutlined /></template>
暂停
</a-button>
<a-button type="primary" @click="handleEdit(record.id)" v-perm="['sys:job:update']">
<template #icon><EditOutlined /></template>
编辑
</a-button>
<a-button
type="primary"
danger
@click="handleDelete(record.id)"
v-perm="['sys:job:delete']"
>
<template #icon><DeleteOutlined /></template>
删除
</a-button>
<a-dropdown>
<a-button class="ant-dropdown-link" @click.prevent>
更多<DownOutlined />
</a-button>
<template #overlay>
<a-menu>
<a-menu-item>
<a href="javascript:;" @click="handleJobLog(record.id)">调度日志</a>
</a-menu-item>
<a-menu-item v-if="record.status == 2">
<a href="javascript:;" @click="handelRunOnce(record.id)">执行一次</a>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</a-space>
</template>
</template>
</BasicTable>
</a-card>
<editDialog
v-if="editVisible"
:jobId="jobId"
v-model:visible="editVisible"
@success="reloadTable('noRefresh')"
/>
<jobLog v-if="editLogVisible" :jobId="jobId" v-model:visible="editLogVisible" />
</PageWrapper>
</template>
<script lang="ts" setup>
import { reactive, ref, h, nextTick, defineAsyncComponent } from 'vue';
import { schemas } from './querySchemas';
import { useForm } from '@/components/Form/index';
import { TableAction } from '@/components/Table';
import {
getJobList,
jobDelete,
jobBatchDelete,
getJobRunOnce,
setJobStatus,
getJobPause,
getJobResume,
} from '@/api/monitor/job';
import { columns } from './columns';
import {
PlusOutlined,
EditOutlined,
DeleteOutlined,
FieldTimeOutlined,
DownOutlined,
} from '@ant-design/icons-vue';
import { Modal, message } from 'ant-design-vue';
import { useRouter } from 'vue-router';
/**
* 导入组件
*/
const editDialog = defineAsyncComponent(() => import('./edit.vue'));
const jobLog = defineAsyncComponent(() => import('./log/index.vue'));
/**
* 定义参数变量
*/
const router = useRouter();
const jobId = ref(0);
const editVisible = ref(false);
const editLogVisible = ref(false);
const selectionData = ref([]);
const tableRef = ref();
/**
* 定义查询参数
*/
const formParams = reactive({
jobName: '',
status: '',
});
/**
* 加载数据列表
* @param res 参数
*/
const loadDataTable = async (res: any) => {
const result = await getJobList({ ...formParams, ...res });
result.records.map((item) => {
if (item.status == 0) {
item.realStatus = false;
} else {
item.realStatus = true;
}
});
return result;
};
/**
* 刷新数据列表
* @param noRefresh 参数
*/
function reloadTable(noRefresh = '') {
tableRef.value.reload(noRefresh ? {} : { pageNo: 1 });
}
/**
* 注册
*/
const [register, {}] = useForm({
rowProps: { gutter: [16, 0] },
colProps: {
xs: 24,
sm: 24,
md: 12,
lg: 8,
xl: 6,
},
labelCol: { span: 6, offset: 0 },
schemas,
});
/**
* 执行提交表单
*/
function handleSubmit(values) {
for (const key in formParams) {
formParams[key] = '';
}
for (const key in values) {
formParams[key] = values[key];
}
reloadTable();
}
/**
* 执行重置
*/
function handleReset() {
for (const key in formParams) {
formParams[key] = '';
}
reloadTable();
}
/**
* 执行添加
*/
const handleAdd = async () => {
jobId.value = 0;
await nextTick();
editVisible.value = true;
};
/**
* 执行设置状态
*/
const handelSetStatus = async (row) => {
await setJobStatus({ id: row.id, status: row.realStatus ? 1 : 0 });
message.success('设置成功');
reloadTable('noRefresh');
};
/**
* 执行编辑
* @param id 参数
*/
const handleEdit = async (id) => {
jobId.value = id;
await nextTick();
editVisible.value = true;
};
/**
* 执行状态发生变化
* @param record 参数
*/
const handelChangeStatus = async (record) => {
Modal.confirm({
title: '提示',
content: `确定要${record.status == 1 ? '暂停' : '启动'}`,
onOk: async () => {
record.status == 1 ? await getJobPause(record.id) : await getJobResume(record.id);
reloadTable('noRefresh');
},
});
};
/**
* 执行一次
*/
const handelRunOnce = async (id) => {
Modal.confirm({
title: '提示',
content: '确定要执行一次?',
onOk: async () => {
await getJobRunOnce(id);
message.success('执行成功');
},
});
};
/**
* 执行删除
* @param id 参数
*/
async function handleDelete(id) {
Modal.confirm({
title: '提示',
content: '确定要删除?',
onOk: async () => {
id ? await jobDelete(id) : await jobBatchDelete(selectionData.value);
message.success('删除成功');
reloadTable();
},
});
}
/**
* 执行查看调度日志
* @param id 参数
*/
const handleJobLog = (id) => {
// router.push({path:'/monitorJob/log'})
editLogVisible.value = true;
jobId.value = id;
};
/**
* 选项发生变化
* @param value 参数
*/
function onSelectionChange(value) {
selectionData.value = value;
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,318 +0,0 @@
<template>
<a-modal
v-model:visible="props.visible"
:title="props.tenantId ? '编辑' : '新增'"
:width="800"
style="top: 20px"
@cancel="dialogClose"
>
<a-form ref="formRef" :model="formData" :label-col="{ style: { width: '140px' } }">
<div class="flex">
<a-form-item
label="租户图片"
name="image"
:rules="{ required: true, message: '请上传租户图片', trigger: 'change' }"
>
<UploadImg
@change-file-name="(name) => (formData.imageImgName = name)"
:fileType="['image/jpeg', 'image/png', 'image/jpg', 'image/gif']"
name="tenant"
:fileSize="200"
v-model:image-url="formData.image"
:cropper="false"
>
<template #tip>支持扩展名: jpg png jpeg;文件大小不超过200M</template>
</UploadImg>
</a-form-item>
</div>
<div class="flex">
<a-form-item
label="名称"
name="name"
class="flex-1"
:rules="{ required: true, message: '请输入名称', trigger: 'blur' }"
>
<a-input v-model:value="formData.name" placeholder="请输入名称" allow-clear />
</a-form-item>
<a-form-item
label="编号"
name="code"
class="flex-1"
:rules="{ required: true, message: '请输入编号', trigger: 'blur' }"
>
<a-input v-model:value="formData.code" allow-clear placeholder="请输入编号" />
</a-form-item>
</div>
<div class="flex">
<a-form-item
label="统一社会信用代码"
name="license"
class="flex-1"
:rules="{ required: true, message: '请输入统一社会信用代码', trigger: 'blur' }"
>
<a-input
v-model:value="formData.license"
placeholder="请输入统一社会信用代码"
allow-clear
/>
</a-form-item>
<a-form-item
label="联系人"
name="contactUser"
class="flex-1"
:rules="{ required: true, message: '请输入联系人', trigger: 'blur' }"
>
<a-input v-model:value="formData.contactUser" placeholder="请输入联系人" allow-clear />
</a-form-item>
</div>
<div class="flex">
<a-form-item
label="联系电话"
name="contactMobile"
class="flex-1"
:rules="{ required: true, message: '请输入联系电话', trigger: 'blur' }"
>
<a-input
v-model:value="formData.contactMobile"
placeholder="请输入联系电话"
allow-clear
/>
</a-form-item>
<a-form-item
label="邮箱地址"
name="contactEmail"
class="flex-1"
:rules="[
{ required: true, message: '请输入邮箱地址', trigger: 'blur' },
{ type: 'email', message: '请输入正确邮箱地址', trigger: 'blur' },
]"
>
<a-input v-model:value="formData.contactEmail" placeholder="请输入邮箱地址" allow-clear />
</a-form-item>
</div>
<div class="flex">
<a-form-item
label="官网地址"
name="contactSite"
class="flex-1"
:rules="{ required: true, message: '请输入官网地址', trigger: 'blur' }"
>
<a-input v-model:value="formData.contactSite" placeholder="请输入官网地址" allow-clear />
</a-form-item>
<a-form-item
label="用户限额"
name="number"
class="flex-1"
:rules="{ required: true, message: '请输入用户限额', trigger: 'blur' }"
>
<number-input v-model="formData.number" placeholder="请输入用户限额" allow-clear />
</a-form-item>
</div>
<div class="flex">
<a-form-item
label="过期时间"
name="expireTime"
class="flex-1"
:rules="{ required: true, message: '请选择过期时间', trigger: 'change' }"
>
<a-date-picker
show-time
placeholder="请选择过期时间"
v-model:value="formData.expireTime"
format="YYYY-MM-DD HH:mm:ss"
valueFormat="YYYY-MM-DD HH:mm:ss"
/>
</a-form-item>
<a-form-item
label="租户地址"
name="contactAddress"
class="flex-1"
:rules="{ required: true, message: '请输入租户地址', trigger: 'blur' }"
>
<a-input
v-model:value="formData.contactAddress"
placeholder="请输入租户地址"
allow-clear
/>
</a-form-item>
</div>
<div class="flex">
<a-form-item
label="简介"
name="contactIntro"
class="flex-1"
:rules="{ required: true, message: '请输入简介', trigger: 'blur' }"
>
<a-input
v-model:value="formData.contactIntro"
type="textarea"
placeholder="请输入简介"
allow-clear
/>
</a-form-item>
</div>
<div class="flex">
<a-form-item label="备注" name="contactNote" class="flex-1">
<a-input
v-model:value="formData.contactNote"
type="textarea"
placeholder="请输入备注"
allow-clear
/>
</a-form-item>
</div>
<div class="flex">
<a-form-item label="租户状态" name="status" class="flex-1">
<a-radio-group v-model:value="formData.status" name="status">
<a-radio :value="0">正常</a-radio>
<a-radio :value="1">禁用</a-radio>
</a-radio-group>
</a-form-item>
</div>
</a-form>
<template #footer>
<span class="dialog-footer">
<a-button @click="dialogClose">取消</a-button>
<a-button :loading="subLoading" type="primary" @click="submit"> 确定 </a-button>
</span>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import { getTenantDetail, tenantAdd, tenantUpdate } from '@/api/system/tenant';
import { onMounted, reactive, shallowRef } from 'vue';
import { getRoleAllList } from '@/api/system/role';
import { getDeptList } from '@/api/system/dept';
import { getLevelAllList } from '@/api/system/level';
import { getPositionAllList } from '@/api/system/position';
import UploadImg from '@/components/Upload/Image.vue';
import { buildTree } from '@/utils/auth';
import type { FormInstance } from 'ant-design-vue';
import { useLockFn } from '@/utils/useLockFn';
/**
* 定义参数变量
*/
const formRef = shallowRef<FormInstance>();
const emit = defineEmits(['success', 'update:visible']);
/**
* 定义接收的参数
*/
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
tenantId: {
type: Number,
required: true,
default: 0,
},
});
/**
* 定义接收的参数
*/
const formData = reactive({
id: 0,
code: '',
name: '',
image: '',
license: '',
contactUser: '',
contactMobile: '',
contactEmail: '',
contactAddress: '',
contactIntro: '',
contactSite: '',
contactNote: '',
expireTime: '',
status: 0,
number: '',
});
const passwordConfirmValidator = (rule: object, value: string, callback: any) => {
if (formData.password) {
if (!value) callback(new Error('请再次输入密码'));
if (value !== formData.password) callback(new Error('两次输入密码不一致!'));
}
callback();
};
/**
* 关闭窗体
*/
const dialogClose = () => {
emit('update:visible', false);
};
/**
* 设置表单数据
* @param row 参数
*/
const setFormData = async (row: any) => {
const data = await getTenantDetail(row.tenantId);
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
formData[key] = data[key];
}
}
};
/**
* 执行提交表单
*/
const handleSubmit = async () => {
console.log(formData);
await formRef.value?.validate();
props.tenantId ? await tenantUpdate(formData) : await tenantAdd(formData);
emit('update:visible', false);
emit('success');
};
const { isLock: subLoading, lockFn: submit } = useLockFn(handleSubmit);
/**
* 定义选项数据
*/
const optionData = reactive({
roleList: [],
deptList: [],
levelList: [],
positionList: [],
});
function uploadChange(data: string[]) {
formData.avatar = data.fileUrl;
formData.avatarName = data.fileName;
}
const handleDelete = async (file) => {
console.log(file);
};
/**
* 获取全部字典数据
*/
const getAllDict = async () => {
let list = await getRoleAllList();
optionData.roleList = list ? list : [];
list = await getDeptList();
optionData.deptList = list ? buildTree(list) : [];
list = await getLevelAllList();
optionData.levelList = list ? list : [];
list = await getPositionAllList();
optionData.positionList = list ? list : [];
};
/**
* 钩子函数
*/
onMounted(() => {
getAllDict();
if (props.tenantId) {
setFormData({ tenantId: props.tenantId });
}
});
</script>

View File

@ -1,119 +0,0 @@
<template>
<a-modal v-model:visible="props.visible" title="文件日志详情" width="800px" @cancel="dialogClose">
<a-descriptions class="margin-top" :column="2" bordered :labelStyle="{ width: '125px' }">
<a-descriptions-item label="文件名称:"
><a :href="formData.filePath" target="_blank">{{
formData.originalName
}}</a></a-descriptions-item
>
<a-descriptions-item label="文件类型:">{{ formData.fileType }}</a-descriptions-item>
<a-descriptions-item label="文件大小:">{{ formData.fileSize }}B</a-descriptions-item>
<a-descriptions-item label="请求耗时:">{{ formData.consumeTime }}s</a-descriptions-item>
<a-descriptions-item label="业务类型:">{{
formData.bizType ? (formData.bizType == 1 ? '订单' : '其他') : ''
}}</a-descriptions-item>
<a-descriptions-item label="业务ID:">{{ formData.bizId }}</a-descriptions-item>
<a-descriptions-item label="业务内容" :span="3">
{{ formData.bizContent }}
</a-descriptions-item>
<a-descriptions-item label="请求状态" :span="3">
{{ formData.status ? '失败' : '成功' }}
</a-descriptions-item>
<a-descriptions-item label="请求参数" :span="3">
{{ formData.param }}
</a-descriptions-item>
<a-descriptions-item label="返回结果" :span="3">
{{ formData.result }}
</a-descriptions-item>
<a-descriptions-item label="错误描述" :span="3">
{{ formData.error }}
</a-descriptions-item>
</a-descriptions>
<template #footer>
<span class="dialog-footer">
<a-button @click="dialogClose">取消</a-button>
</span>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import { getFileLogDetail } from '@/api/logger/fileLog';
import { onMounted, ref } from 'vue';
const emit = defineEmits(['success', 'update:visible']);
const formData = ref({});
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
fileId: {
type: Number,
required: true,
default: 0,
},
});
const dialogClose = () => {
emit('update:visible', false);
};
const setFormData = async () => {
const data = await getFileLogDetail(props.fileId);
formData.value = data;
};
const getReviceType = (type) => {
let typeText = '';
switch (type) {
case 1:
typeText = '系统用户';
break;
case 2:
typeText = '会员用户';
break;
case 3:
typeText = '其他';
break;
default:
break;
}
return typeText;
};
// 此处作为经典案例,禁止删除
const getTyepText = (type) => {
let typeText = '';
switch (type) {
case 1:
typeText = '登录';
break;
case 2:
typeText = '注册';
break;
case 3:
typeText = '找回密码';
break;
case 4:
typeText = '业务';
break;
case 5:
typeText = '其他';
break;
default:
break;
}
return typeText;
};
onMounted(() => {
if (props.fileId) {
setFormData();
}
});
</script>
<style lang="less" scoped>
:deep(.ant-descriptions__body .ant-descriptions__table .ant-descriptions__cell) {
word-break: break-all;
}
</style>

View File

@ -1,182 +0,0 @@
<template>
<a-modal
v-model:visible="props.visible"
:title="dialogTitle"
width="1350px"
style="top:15px;"
@cancel="dialogClose"
>
<a-form style="display: flex" ref="formRef" :model="formData" :label-col="{ style: { width: '80px' }}">
<div style="width: 880px;flex: none" :style="{ height: fwbHeight + 'px' }">
<a-form-item label-width="0px" name="content">
<Editor ref="editorRef" :height="fwbHeight" name="content" />
</a-form-item>
</div>
<div style="flex:1;margin-left: 10px">
<a-form-item label="广告标题" name="title" :rules="{ required: true, message: '请输入广告标题', trigger: 'blur' }">
<a-input placeholder="请输入广告标题" :maxlength="50" v-model:value="formData.title"></a-input>
</a-form-item>
<a-form-item label="广告位" name="adSortId" class="flex-1"
:rules="{ required: true, message: '请选择广告位', trigger: 'change' }">
<a-select v-model:value="formData.adSortId" class="flex-1" allow-clear placeholder="请选择广告位">
<a-select-option v-for="(item, index) in adSortList" :key="index" :value="item.id">{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="广告格式" name="type" :rules="{ required: true, message: '请选择广告格式', trigger: 'change' }">
<a-select v-model:value="formData.type" placeholder="请选择广告格式">
<a-select-option :value="1">图片</a-select-option>
<a-select-option :value="2">文字</a-select-option>
<a-select-option :value="3">视频</a-select-option>
<a-select-option :value="4">推荐</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="广告封面" name="cover" :rules="{ required: true, message: '请上传广告封面', trigger: 'change' }">
<UploadImg
:fileType="['image/jpeg', 'image/png', 'image/jpg', 'image/gif']" name="ad" :fileSize="200"
v-model:image-url="formData.cover">
<template v-slot:tip>支持扩展名: jpg png jpeg;文件大小不超过200M</template>
</UploadImg>
</a-form-item>
<a-form-item label="广告链接" name="url" :rules="{ required: true, message: '请输入广告链接', trigger: 'blur' }">
<a-input v-model:value="formData.url" type="textarea" placeholder="请输入广告链接" />
</a-form-item>
<a-form-item label="广告宽度" name="width"
:rules="{ required: true, message: '请输入广告宽度', trigger: 'change' }">
<number-input v-model:value="formData.width" placeholder="请输入广告宽度" allow-clear />
</a-form-item>
<a-form-item label="广告高度" name="height"
:rules="{ required: true, message: '请输入广告高度', trigger: 'blur' }">
<number-input v-model:value="formData.height" placeholder="请输入广告高度" allow-clear />
</a-form-item>
<a-form-item label="广告时间" name="adTime" class="flex-1" :rules="{ required: true, message: '请选择广告时间', trigger: 'change' }">
<a-range-picker v-model:value="formData.adTime" value-format="YYYY-MM-DD HH:mm:ss" style="width:100%"
:show-time="{ format: 'HH:mm' }" :placeholder="['开始时间', '结束时间']">
</a-range-picker>
</a-form-item>
<a-form-item label="点击率" name="click" :rules="{ required: true, message: '请输入点击率', trigger: 'blur' }">
<number-input v-model:value="formData.click" placeholder="请输入点击率" allow-clear />
</a-form-item>
<a-form-item label="广告描述" name="note" :rules="{ required: true, message: '请输入备注', trigger: 'blur' }">
<a-input v-model:value="formData.note" type="textarea" placeholder="请输入广告描述" />
</a-form-item>
<a-form-item label="排序" name="sort">
<a-input-number v-model:value="formData.sort" :max="9999" placeholder="请输入排序" />
</a-form-item>
<a-form-item label="状态">
<a-radio-group v-model:value="formData.status" name="status">
<a-radio :value="1">在用</a-radio>
<a-radio :value="2">停用</a-radio>
</a-radio-group>
</a-form-item>
</div>
</a-form>
<template #footer>
<span class="dialog-footer">
<a-button @click="dialogClose">取消</a-button>
<a-button :loading="subLoading" type="primary" @click="submit">确认</a-button>
</span>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import { adAdd, adUpdate, getAdDetail } from '@/api/content/ad';
import { getAdSortAllList } from '@/api/content/adSort';
import { computed, onMounted, ref, shallowRef, reactive } from "vue";
import type { FormInstance } from 'ant-design-vue';
const formRef = shallowRef<FormInstance>();
import UploadImg from "@/components/Upload/Image.vue";
import { useLockFn } from "@/utils/useLockFn";
import Editor from '@/components/Editor/tinymce.vue'
import { message } from 'ant-design-vue'
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false
},
adId: {
type: Number,
required: true,
default: 0
},
searchParamData: {
type: Object,
default: {}
}
});
const adSortList = ref([])
const adTime = ref([])
const emit = defineEmits(["success", "update:visible"]);
const dialogTitle = computed(() => {
return props.adId ? "编辑内容" : "新增内容";
});
const fwbHeight = document.body.clientHeight - 180
const formData = reactive({
id: "",
title: "",
adSortId: undefined,
cover: '',
type: undefined,
note: '',
content: '',
url: '',
width: "",
height: "",
adTime:[],
startTime: '',
endTime: '',
click: '',
status: 1,
sort: 0,
});
const dialogClose = () => {
emit("update:visible", false);
};
const setFormData = async () => {
const data = await getAdDetail(props.adId);
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
formData[key] = data[key];
}
}
formData.adTime = [formData.startTime,formData.endTime]
editorRef.value.myValue = formData.content
};
const editorRef = ref()
const handleSubmit = async () => {
formData.startTime = formData.adTime.length>0?formData.adTime[0]:''
formData.endTime = formData.adTime.length>0?formData.adTime[1]:''
await formRef.value?.validate();
let ruleForm = JSON.parse(JSON.stringify(formData));
ruleForm.content = editorRef.value.myValue
if (!ruleForm.content) {
message.error("请添加文章内容");
return;
}
props.adId ? await adUpdate(ruleForm) : await adAdd(ruleForm);
message.success("操作成功");
emit("update:visible", false);
emit("success");
};
const { isLock: subLoading, lockFn: submit } = useLockFn(handleSubmit);
const getAllDict = async () => {
let list = await getAdSortAllList();
adSortList.value = list ? list : [];
};
onMounted(() => {
getAllDict()
if (props.adId) {
setFormData();
}
});
</script>

View File

@ -1,164 +0,0 @@
<template>
<div ref="chartRef" :style="{ height, width }"></div>
</template>
<script lang="ts" setup>
import { onMounted, PropType, ref, Ref } from 'vue';
import { useECharts } from '@/hooks/web/useECharts';
defineProps({
width: {
type: String as PropType<string>,
default: '100%',
},
height: {
type: String as PropType<string>,
default: '350px',
},
});
const chartRef = ref<HTMLDivElement | null>(null);
const { setOptions, echarts } = useECharts(chartRef as Ref<HTMLDivElement>);
const option = {
xAxis: {
type: 'category',
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
},
yAxis: {
type: 'value',
},
tooltip: {
show: true,
},
series: [
{
data: [
{
value: 8765,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#2378f7' },
{ offset: 0.7, color: '#2378f7' },
{ offset: 1, color: '#83bff6' },
]),
},
},
{
value: 4598,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#2378f7' },
{ offset: 0.7, color: '#2378f7' },
{ offset: 1, color: '#83bff6' },
]),
},
},
{
value: 13567,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#2378f7' },
{ offset: 0.7, color: '#2378f7' },
{ offset: 1, color: '#83bff6' },
]),
},
},
{
value: 4789,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#2378f7' },
{ offset: 0.7, color: '#2378f7' },
{ offset: 1, color: '#83bff6' },
]),
},
},
{
value: 9876,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#2378f7' },
{ offset: 0.7, color: '#2378f7' },
{ offset: 1, color: '#83bff6' },
]),
},
},
{
value: 5478,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#2378f7' },
{ offset: 0.7, color: '#2378f7' },
{ offset: 1, color: '#83bff6' },
]),
},
},
{
value: 3289,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#2378f7' },
{ offset: 0.7, color: '#2378f7' },
{ offset: 1, color: '#83bff6' },
]),
},
},
{
value: 13423,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#2378f7' },
{ offset: 0.7, color: '#2378f7' },
{ offset: 1, color: '#83bff6' },
]),
},
},
{
value: 6543,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#2378f7' },
{ offset: 0.7, color: '#2378f7' },
{ offset: 1, color: '#83bff6' },
]),
},
},
{
value: 7689,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#2378f7' },
{ offset: 0.7, color: '#2378f7' },
{ offset: 1, color: '#83bff6' },
]),
},
},
{
value: 8235,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#2378f7' },
{ offset: 0.7, color: '#2378f7' },
{ offset: 1, color: '#83bff6' },
]),
},
},
{
value: 6578,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#2378f7' },
{ offset: 0.7, color: '#2378f7' },
{ offset: 1, color: '#83bff6' },
]),
},
},
],
type: 'bar',
},
],
};
onMounted(() => {
setOptions(option as any);
});
</script>

View File

@ -1,43 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 短信日志列表
*/
export function getSmsLogList(params?) {
return http.request({
url: '/sms/log/page',
method: 'GET',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getSmsLogDetail(id) {
return http.request({
url: '/sms/log/detail/' + id,
method: 'get',
});
}
/**
* @description: 删除登录日志
*/
export function smsLogDelete(id) {
return http.request({
url: '/sms/log/delete/' + id,
method: 'DELETE',
});
}
/**
* @description: 批量删除登录日志
*/
export function smsLogBatchDelete(data: any) {
return http.request({
url: '/sms/log/batchDelete',
method: 'DELETE',
data,
});
}

View File

@ -1,39 +0,0 @@
<template>
<a-card
:bordered="false"
bodyStyle="padding: 0;width:100%"
class="page-wrapper-footer"
:class="{ 'dark-bg': getDarkTheme }"
>
<div class="flex items-center w-full">
<div class="flex-1 page-wrapper-footer-left"><slot name="left"></slot></div>
<div class="page-wrapper-footer-right"><slot name="right"></slot></div>
</div>
</a-card>
</template>
<script lang="ts" setup>
import { useProjectSetting } from '@/hooks/setting/useProjectSetting';
const { getDarkTheme } = useProjectSetting();
</script>
<style lang="less" scoped>
.page-wrapper-footer {
position: fixed;
right: 0;
bottom: 0;
z-index: 999;
display: flex;
width: 100%;
align-items: center;
padding: 15px 24px;
box-shadow: -3px 1px 2px -2px rgba(0, 0, 0, 0.08), 0 3px 6px 0 rgba(0, 0, 0, 0.08),
-3px 5px 12px 4px rgba(0, 0, 0, 0.08);
transition: width 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
background: #fff;
}
.dark-bg {
background: rgb(24, 24, 28);
}
</style>

View File

@ -1,129 +0,0 @@
<template>
<PageWrapper>
<a-card :bordered="false" class="pt-3 mb-3 proCard">
<BasicForm @register="register" @submit="handleSubmit" @reset="handleReset"></BasicForm>
</a-card>
<a-card :bordered="false" class="proCard">
<BasicTable
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
ref="tableRef"
:row-selection="{onChange: onSelectionChange}"
>
<template #tableTitle>
<a-button type="danger" @click="handleDelete()" :disabled="!selectionData.length" v-perm="['sys:loginLog:batchDelete']">
<template #icon>
<DeleteOutlined />
</template>
删除
</a-button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<a-space>
<a-button type="primary" @click="handleInfo(record.id)" v-perm="['sys:loginLog:detail']">
<template #icon><EditOutlined /></template>
详情
</a-button>
<a-button type="primary" danger @click="handleDelete(record.id)" v-perm="['sys:loginLog:delete']">
<template #icon><DeleteOutlined /></template>
删除
</a-button>
</a-space>
</template>
</template>
</BasicTable>
</a-card>
<editDialog
v-if="editVisible"
:loginlogId="loginlogId"
v-model:visible="editVisible"
@success="reloadTable('noRefresh')"
>
</editDialog>
</PageWrapper>
</template>
<script lang="ts" setup>
import { reactive, ref, h,nextTick,defineAsyncComponent } from 'vue';
import { EditOutlined,DeleteOutlined} from '@ant-design/icons-vue';
import { schemas } from './loginLog/querySchemas';
import { useForm } from '@/components/Form/index';
import { TableAction } from '@/components/Table';
import { getLoginLogList,loginLogDelete,loginLogBatchDelete } from '@/api/system/loginLog';
import { columns } from './loginLog/columns';
import { Modal,message } from 'ant-design-vue';
const editDialog = defineAsyncComponent(() =>
import('./loginLog/edit.vue')
)
const loginlogId =ref(0)
const editVisible=ref(false)
const selectionData = ref([])
const tableRef = ref();
const formParams = reactive({
username:'',
type:'',
status:''
});
const loadDataTable = async (res: any) => {
const result = await getLoginLogList({ ...formParams, ...res });
return result;
};
function reloadTable(noRefresh='') {
tableRef.value.reload(noRefresh?{}:{pageNo:1});
}
const [register, {}] = useForm({
rowProps: { gutter: [16, 0] },
colProps: {
xs: 24,
sm: 24,
md: 12,
lg: 8,
xl: 6,
},
labelCol: { span: 6, offset: 0 },
schemas
});
function handleSubmit(values) {
for (const key in formParams) {
formParams[key] ='';
}
for (const key in values) {
formParams[key] = values[key]
}
reloadTable();
}
function handleReset() {
for (const key in formParams) {
formParams[key] ='';
}
reloadTable();
}
const handleInfo = async (id) => {
loginlogId.value=id
await nextTick();
editVisible.value=true
};
async function handleDelete(id) {
Modal.confirm({
title: '提示',
content: "确定要删除?",
onOk: async () => {
id? await loginLogDelete(id):await loginLogBatchDelete(selectionData.value);
message.success("删除成功");
reloadTable()
}
});
}
function onSelectionChange(value){
selectionData.value = value
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,81 +0,0 @@
import { h } from 'vue';
import { Tag } from 'ant-design-vue';
export const columns = [
{
title: '部门名称',
dataIndex: 'name',
key: 'name',
width: 200,
},
{
title: '部门类型',
dataIndex: 'type',
key: 'type',
width: 100,
customRender({ record }) {
let typeText = '';
let color = '';
switch (record.type) {
case 1:
typeText = '公司';
color = 'processing';
break;
case 2:
typeText = '子公司';
color = 'success';
break;
case 3:
typeText = '部门';
color = 'warning';
break;
case 4:
typeText = '小组';
color = 'default';
break;
default:
break;
}
return h(
Tag,
{
color: color,
},
{
default: () => typeText,
},
);
},
},
{
title: '部门排序',
dataIndex: 'sort',
key: 'sort',
width: 100,
},
{
title: '部门备注',
dataIndex: 'note',
key: 'note',
width: 100,
},
{
title: '创建人',
dataIndex: 'createUser',
key: 'createUser',
width: 100,
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
width: 180,
},
{
title: '操作',
fixed: 'right',
dataIndex: 'action',
key: 'action',
width: 200,
},
];

View File

@ -1,60 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 列表
*/
export function getFileTemplateList(params?) {
return http.request({
url: '/file/template/page',
method: 'GET',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getFileTemplateDetail(id) {
return http.request({
url: '/file/template/detail/' + id,
method: 'get',
});
}
/**
* @description: 添加
*/
export function fileTemplateAdd(data: any) {
return http.request({
url: '/file/template/add',
method: 'POST',
data,
});
}
/**
* @description: 更新
*/
export function fileTemplateUpdate(data: any) {
return http.request({
url: '/file/template/update',
method: 'PUT',
data,
});
}
/**
* @description: 删除
*/
export function fileTemplateDelete(id) {
return http.request({
url: '/file/template/delete/' + id,
method: 'DELETE',
});
}
/**
* @description: 批量删除
*/
export function fileTemplateBatchDelete(data: any) {
return http.request({
url: '/file/template/batchDelete',
method: 'DELETE',
data,
});
}

View File

@ -1,158 +0,0 @@
<template>
<PageWrapper>
<a-card :bordered="false" class="pt-3 mb-3 proCard">
<BasicForm @register="register" @submit="handleSubmit" @reset="handleReset">
<template #statusSlot="{ model, field }">
<a-input v-model="model[field]" />
</template>
</BasicForm>
</a-card>
<a-card :bordered="false" class="proCard">
<BasicTable
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
ref="tableRef"
scroll-x="1200"
:row-selection="{ onChange: onSelectionChange }"
virtual-scroll
>
<template #tableTitle>
<a-space>
<a-button type="primary" @click="handleAdd" v-perm="['sys:article:add']">
<template #icon>
<PlusOutlined />
</template>
添加文章
</a-button>
<a-button
type="danger"
@click="handleDelete()"
:disabled="!selectionData.length"
v-perm="['sys:article:batchDelete']"
>
<template #icon>
<DeleteOutlined />
</template>
删除
</a-button>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<a-space>
<a-button
type="primary"
@click="handleEdit(record.id)"
v-perm="['sys:article:update']"
>
<template #icon><EditOutlined /></template>
编辑
</a-button>
<a-button
type="primary"
danger
@click="handleDelete(record.id)"
v-perm="['sys:article:delete']"
>
<template #icon><DeleteOutlined /></template>
删除
</a-button>
</a-space>
</template>
</template>
</BasicTable>
</a-card>
<editDialog
v-if="editVisible"
:articleId="articleId"
v-model:visible="editVisible"
@success="reloadTable('noRefresh')"
/>
</PageWrapper>
</template>
<script lang="ts" setup>
import { nextTick, reactive, ref, defineAsyncComponent } from 'vue';
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue';
import { useForm } from '@/components/Form/index';
import { getArticleList, articleDelete, articleBatchDelete } from '@/api/content/article';
import { columns } from './columns';
import { schemas } from './querySchemas';
import { Modal, message } from 'ant-design-vue';
const articleId = ref(0);
const tableRef = ref();
const editVisible = ref(false);
const selectionData = ref([]);
const editDialog = defineAsyncComponent(() => import('./edit.vue'));
const formParams = reactive({
title: '',
status: '',
});
const loadDataTable = async (res) => {
const result = await getArticleList({ ...formParams, ...res });
return result;
};
function reloadTable(noRefresh = '') {
tableRef.value.reload(noRefresh ? {} : { pageNo: 1 });
}
async function handleEdit(id) {
articleId.value = id;
await nextTick();
editVisible.value = true;
}
async function handleDelete(id) {
Modal.confirm({
title: '提示',
content: '确定要删除?',
onOk: async () => {
id ? await articleDelete(id) : await articleBatchDelete(selectionData.value);
message.success('删除成功');
reloadTable();
},
});
}
function handleSubmit(values: Recordable) {
for (const key in formParams) {
formParams[key] = '';
}
for (const key in values) {
formParams[key] = values[key];
}
reloadTable();
}
function handleReset(values) {
for (const key in formParams) {
formParams[key] = '';
}
reloadTable();
}
function onSelectionChange(value) {
selectionData.value = value;
}
const [register, {}] = useForm({
rowProps: { gutter: [16, 0] },
colProps: {
xs: 24,
sm: 24,
md: 12,
lg: 8,
xl: 6,
},
labelCol: { span: 6, offset: 0 },
schemas,
});
//添加
const handleAdd = async () => {
articleId.value = 0;
await nextTick();
editVisible.value = true;
};
</script>

View File

@ -1,76 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 获取租户列表
*/
export function getTenantList(params) {
return http.request({
url: '/admin/tenant/page',
method: 'get',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getTenantDetail(tenantId) {
return http.request({
url: '/admin/tenant/detail/' + tenantId,
method: 'get',
});
}
/**
* @description: 添加租户
*/
export function tenantAdd(data: any) {
return http.request({
url: '/admin/tenant/add',
method: 'POST',
data,
});
}
/**
* @description: 更新租户
*/
export function tenantUpdate(data: any) {
return http.request({
url: '/admin/tenant/update',
method: 'PUT',
data,
});
}
/**
* @description: 删除租户
*/
export function tenantDelete(tenantId) {
return http.request({
url: '/admin/tenant/delete/' + tenantId,
method: 'DELETE',
});
}
/**
* @description: 批量删除租户
*/
export function tenantBatchDelete(data: any) {
return http.request({
url: '/admin/tenant/batchDelete',
method: 'DELETE',
data,
});
}
/**
* @description: 创建租户账号
*/
export function tenantAccount(data: any) {
return http.request({
url: '/admin/tenant/account',
method: 'POST',
data,
});
}

View File

@ -1,241 +0,0 @@
<template>
<PageWrapper>
<a-row :gutter="10" class="mt-3">
<a-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6">
<a-card shadow="hover" class="border-0">
<template #title>
<a-row>
<a-col :span="10">
<a-input
type="text"
v-model:value="params.name"
placeholder="请输入字典名称"
allow-clear
/>
</a-col>
<a-col :span="14" style="text-align: right">
<a-button
type="primary"
@click="
pager.page = 1;
loadDataTable();
"
>
<template #icon> <SearchOutlined /> </template>查询
</a-button>
<a-button
type="primary"
@click="dictRefresh"
style="margin-left: 8px"
v-perm="['sys:dict:cache']"
>
<template #icon> <RedoOutlined /> </template>刷新缓存</a-button
>
</a-col>
</a-row>
<div style="margin-top: 15px">
<a-space>
<a-button type="primary" @click="handleAdd" v-perm="['sys:dict:add']">
<template #icon>
<PlusOutlined />
</template>
新建
</a-button>
<a-button type="warning" @click="handleEdit" v-perm="['sys:dict:edit']">
<template #icon> <EditOutlined /> </template>编辑
</a-button>
<a-button type="danger" @click="handleDelete()" v-perm="['sys:dict:delete']">
<template #icon> <DeleteOutlined /> </template>删除
</a-button>
</a-space>
</div>
</template>
<div :style="{ height: fwbHeight + 'px' }" class="dict-list-box">
<div
v-for="(item, index) in dictDataList"
:key="index"
@click="onCheckedRow(item)"
class="dict-item"
:class="item.id == dictId ? 'active' : ''"
>
<span class="t1"
>{{ item.name }}<span class="t2">({{ item.code }})</span></span
>
</div>
</div>
<pagination
style="justify-content: flex-end"
class="mt-10 flex"
@change="loadDataTable"
v-model="pager"
/>
</a-card>
</a-col>
<a-col :xs="24" :sm="24" :md="18" :lg="18" :xl="18">
<a-card shadow="hover" class="mb-4 border-0 proCard">
<dictItem :dictId="dictId" v-if="dictItemShow" />
</a-card>
</a-col>
</a-row>
<editDialog
v-if="editVisible"
:dictId="dictId"
v-model:visible="editVisible"
@success="loadDataTable()"
/>
</PageWrapper>
</template>
<script lang="ts" setup>
import { ref, nextTick, defineAsyncComponent, onMounted } from 'vue';
import { SearchOutlined } from '@ant-design/icons-vue';
import { getDictList, refreshCache, dictDelete } from '@/api/data/dictionary';
import { PlusOutlined, EditOutlined, DeleteOutlined, RedoOutlined } from '@ant-design/icons-vue';
import dictItem from './dictItem.vue';
import { Modal, message } from 'ant-design-vue';
/**
* 导入组件
*/
const editDialog = defineAsyncComponent(() => import('./edit.vue'));
/**
* 定义参数变量
*/
const dictId = ref(0);
const dictItemShow = ref(false);
const editVisible = ref(false);
/**
* 定义查询参数
*/
const params = ref({
name: '',
});
const dictDataList = ref([]);
/**
* 定义分页参数
*/
const pager = ref({
page: 1,
size: 20,
count: dictDataList.value.length,
});
const fwbHeight = document.body.clientHeight - 390;
/**
* 添加字典
*/
const handleAdd = async () => {
await nextTick();
editVisible.value = true;
};
/**
* 刷新缓存
*/
async function dictRefresh() {
await refreshCache();
message.success('刷新成功');
}
/**
* 执行编辑
*/
const handleEdit = () => {
editVisible.value = true;
};
/**
* 数据行选中事件
* @param row 参数
*/
function onCheckedRow(row) {
dictId.value = row.id;
}
/**
* 加载数据列表
*/
const loadDataTable = async () => {
const result = await getDictList({
...params.value,
pageNo: pager.value.page,
pageSize: pager.value.size,
});
dictId.value = result?.records[0]?.id;
dictItemShow.value = true;
dictDataList.value = result.records;
pager.value.count = result.total;
};
/**
* 执行删除
*/
async function handleDelete() {
Modal.confirm({
title: '提示',
content: '确定要删除?',
onOk: async () => {
dictDelete(dictId.value);
message.success('删除成功');
pager.value.page = 1;
loadDataTable();
},
});
}
/**
* 钩子函数
*/
onMounted(() => {
loadDataTable();
});
</script>
<style lang="less" scoped>
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.dict-list-box {
overflow: auto;
.dict-item {
height: 40px;
line-height: 40px;
padding: 0 6px;
cursor: pointer;
display: flex;
justify-content: space-between;
.t1 {
font-size: 14px;
display: block;
font-weight: 700;
.t2 {
font-size: 12px;
font-weight: normal;
}
}
&.active {
background-color: #e8f1ff;
border-radius: 3px;
.t1 {
color: #1677ff;
}
.t2 {
color: rgb(22, 119, 255, 0.8);
}
}
.ant-badge__content.is-fixed {
top: 20px;
right: calc(-10px + var(--ant-badge-size) / 2);
}
}
}
</style>

View File

@ -1,142 +0,0 @@
<template>
<a-modal
v-model:visible="props.visible"
:title="props.noticeId ? '编辑' : '新增'"
:width="`${size}px`"
@cancel="dialogClose"
style="top: 20px"
>
<a-form
class="ls-form"
ref="formRef"
:model="formData"
:label-col="{ style: { width: '80px' } }"
>
<a-form-item
label="通知标题"
name="title"
:rules="{ required: true, message: '请输入通知标题', trigger: 'blur' }"
>
<a-input class="ls-input" v-model:value="formData.title" placeholder="通知标题" clearable />
</a-form-item>
<a-form-item label="通知类型">
<a-select v-model:value="formData.type" placeholder="请选择通知类型">
<a-select-option :value="1">通知</a-select-option>
<a-select-option :value="2">公告</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="通知状态" name="status">
<a-radio-group v-model:value="formData.status" name="status">
<a-radio :value="1">正常</a-radio>
<a-radio :value="2">关闭</a-radio>
</a-radio-group>
</a-form-item>
<div class="flex">
<a-form-item
class="flex-1"
label="通知内容"
name="content"
:rules="{ required: true, message: '请输入通知内容', trigger: 'blur' }"
>
<Editor ref="editorRef" :height="fwbHeight" class="flex-1" name="notice" />
</a-form-item>
</div>
</a-form>
<template #footer>
<span class="dialog-footer">
<a-button @click="dialogClose">取消</a-button>
<a-button :loading="subLoading" type="primary" @click="submit"> 确定 </a-button>
</span>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'element-plus';
import { getNoticeDetail, noticeAdd, noticeUpdate } from '@/api/data/notice';
import { onMounted, reactive, shallowRef, ref } from 'vue';
import Editor from '@/components/Editor/tinymce.vue';
import { message } from 'ant-design-vue';
import { useLockFn } from '@/utils/useLockFn';
/**
* 定义参数变量
*/
const size = document.body.clientWidth - 500;
const emit = defineEmits(['success', 'update:visible']);
const formRef = shallowRef<FormInstance>();
const editorRef = ref();
/**
* 定义表单参数
*/
const formData = reactive({
id: '',
title: '',
status: 1,
type: 1,
content: '',
});
/**
* 定义接收的参数
*/
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
noticeId: {
type: Number,
required: true,
default: 0,
},
});
const fwbHeight = document.body.clientHeight - 400;
/**
* 执行提交表单
*/
const handleSubmit = async () => {
formData.content = editorRef.value.myValue;
await formRef.value?.validate();
let ruleForm = JSON.parse(JSON.stringify(formData));
ruleForm.content = editorRef.value.myValue;
props.noticeId ? await noticeUpdate(ruleForm) : await noticeAdd(ruleForm);
message.success('操作成功');
emit('update:visible', false);
emit('success');
};
/**
* 关闭窗体
*/
const dialogClose = () => {
emit('update:visible', false);
};
const { isLock: subLoading, lockFn: submit } = useLockFn(handleSubmit);
/**
* 设置表单数据
*/
const setFormData = async () => {
const data = await getNoticeDetail(props.noticeId);
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key];
}
}
editorRef.value.myValue = formData.content;
};
/**
* 钩子函数
*/
onMounted(() => {
if (props.noticeId) {
setFormData();
}
});
</script>

View File

@ -1,71 +0,0 @@
import { h } from 'vue';
import { Tag } from 'ant-design-vue';
export const columns = [
{
title: '城市名称',
dataIndex: 'name',
key: 'name',
width: 100,
},
{
title: '城市拼音',
dataIndex: 'pinyin',
key: 'pinyin',
width: 100,
},
{
title: '城市级别',
dataIndex: 'level',
key: 'level',
width: 100,
customRender({ record }) {
let levelText = '';
switch (record.level) {
case 0:
levelText = '省份';
break;
case 1:
levelText = '城市';
break;
case 2:
levelText = '县区';
break;
case 3:
levelText = '街道';
break;
case 4:
levelText = '居委会';
break;
default:
break;
}
return h('span', levelText || '-');
},
},
{
title: '城市区号',
dataIndex: 'cityCode',
key: 'cityCode',
width: 100,
},
{
title: '行政编码',
dataIndex: 'areaCode',
key: 'areaCode',
width: 100,
},
{
title: '城市邮编',
dataIndex: 'zipCode',
key: 'zipCode',
width: 100,
},
{
title: '操作',
width: 200,
fixed: 'right',
key: 'action',
dataIndex: 'action',
},
];

View File

@ -1,103 +0,0 @@
<template>
<PageWrapper>
<a-card :bordered="false" class="pt-3 mb-3 proCard">
<BasicForm @register="register" @submit="handleSubmit" @reset="handleReset" />
</a-card>
<a-card :bordered="false" class="proCard">
<a-table
:columns="columns"
:style="{ minHeight: fwbHeight + 'px' }"
:scroll="{ x: '100%', y: fwbHeight + 'px' }"
:pagination="{ hideOnSinglePage: true }"
:dataSource="onlineTableData.slice((pager.page - 1) * pager.size, pager.page * pager.size)"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<a-space>
<a-button type="danger" @click="handleDelete(record.tokenId)">
<template #icon><EditOutlined /></template>
强退
</a-button>
</a-space>
</template>
</template>
</a-table>
<pagination
style="justify-content: flex-end"
class="mt-10 flex"
v-model="pager"
@change="loadDataTable"
/>
</a-card>
</PageWrapper>
</template>
<script lang="ts" setup>
import { reactive, ref, onMounted } from 'vue';
import { columns } from './columns';
import { schemas } from './querySchemas';
import { useForm } from '@/components/Form/index';
import { getOnlineList, onlineOut } from '@/api/monitor/online';
import { Modal, message } from 'ant-design-vue';
const onlineTableData = ref([]);
const formParams = reactive({
ipAddr: '',
username: '',
});
const pager = ref({
page: 1,
size: 10,
count: onlineTableData.value.length,
});
const fwbHeight = document.body.clientHeight - 420;
const loadTable = async () => {
onlineTableData.value = await getOnlineList({ ...formParams });
pager.value.count = onlineTableData.value.length;
};
const [register, {}] = useForm({
rowProps: { gutter: [16, 0] },
colProps: {
xs: 24,
sm: 24,
md: 12,
lg: 8,
xl: 6,
},
labelCol: { span: 6, offset: 0 },
schemas,
});
function handleSubmit(values) {
for (const key in formParams) {
formParams[key] = '';
}
for (const key in values) {
formParams[key] = values[key];
}
loadTable();
}
function handleReset() {
for (const key in formParams) {
formParams[key] = '';
}
pager.value.page = 1;
loadTable();
}
async function handleDelete(id) {
Modal.confirm({
title: '提示',
content: '确定要强退?',
onOk: async () => {
await onlineOut(id);
message.success('强退成功');
loadTable();
},
});
}
onMounted(() => {
loadTable();
});
</script>
<style lang="scss" scoped></style>

View File

@ -1,68 +0,0 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
line-height: 1.4;
margin: 1rem auto;
max-width: 900px;
}
table {
border-collapse: collapse;
}
/* Apply a default padding if legacy cellpadding attribute is missing */
table:not([cellpadding]) th,
table:not([cellpadding]) td {
padding: 0.4rem;
}
/* Set default table styles if a table has a positive border attribute
and no inline css */
table[border]:not([border="0"]):not([style*="border-width"]) th,
table[border]:not([border="0"]):not([style*="border-width"]) td {
border-width: 1px;
}
/* Set default table styles if a table has a positive border attribute
and no inline css */
table[border]:not([border="0"]):not([style*="border-style"]) th,
table[border]:not([border="0"]):not([style*="border-style"]) td {
border-style: solid;
}
/* Set default table styles if a table has a positive border attribute
and no inline css */
table[border]:not([border="0"]):not([style*="border-color"]) th,
table[border]:not([border="0"]):not([style*="border-color"]) td {
border-color: #ccc;
}
figure {
display: table;
margin: 1rem auto;
}
figure figcaption {
color: #999;
display: block;
margin-top: 0.25rem;
text-align: center;
}
hr {
border-color: #ccc;
border-style: solid;
border-width: 1px 0 0 0;
}
code {
background-color: #e8e8e8;
border-radius: 3px;
padding: 0.1rem 0.2rem;
}
.mce-content-body:not([dir=rtl]) blockquote {
border-left: 2px solid #ccc;
margin-left: 1.5rem;
padding-left: 1rem;
}
.mce-content-body[dir=rtl] blockquote {
border-right: 2px solid #ccc;
margin-right: 1.5rem;
padding-right: 1rem;
}

View File

@ -1,30 +0,0 @@
import { FormSchema } from '@/components/Form/index';
export const schemas: FormSchema[] = [
{
name: 'name',
component: 'Input',
label: '岗位名称',
componentProps: {
placeholder: '请输入岗位名称',
},
},
{
name: 'status',
component: 'Select',
label: '状态',
componentProps: {
placeholder: '请选择状态',
clearable: true,
options: [
{
label: '正常',
value: '1',
},
{
label: '停用',
value: '2',
},
],
},
},
];

View File

@ -1,66 +0,0 @@
import { h } from 'vue';
export const columns = [
{
title:'ID',
dataIndex: 'id',
},
{
title: '模板名称',
dataIndex: 'title',
},
{
title: '模板编码',
dataIndex: 'code',
},
{
title: '模板类型',
dataIndex: 'type',
customRender({ record }) {
let typeText = ''
switch (record.type) {
case 1:
typeText='普通邮件'
break;
case 2:
typeText='图文邮件'
break;
case 3:
typeText='模板文件'
break;
default:
break;
}
return h('span', typeText || '-');
},
},
{
title: '文件名称',
dataIndex: 'fileName',
},
{
title: '文件路径',
dataIndex: 'filePath',
customRender({ record }) {
return h('a', {
href: record.filePath,
target:"_blank"
}, "点击查看文件");
},
},
{
title: '创建人',
dataIndex: 'createUser',
},
{
title: '创建时间',
dataIndex: 'createTime',
},
{
title: '操作',
fixed:'right',
dataIndex: 'action',
key: 'action',
width: 200,
},
];

View File

@ -1,78 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 列表
*/
export function getAdSortList(params?) {
return http.request({
url: '/admin/ad/sort/page',
method: 'GET',
params,
});
}
/**
* 获取全部推荐位列表
* @param params 参数
* @returns 返回结果
*/
export function getAdSortAllList(params?) {
return http.request({
url: '/admin/ad/sort/list',
method: 'GET',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getAdSortDetail(adSortId) {
return http.request({
url: '/admin/ad/sort/detail/' + adSortId,
method: 'get',
});
}
/**
* @description: 添加
*/
export function adSortAdd(data: any) {
return http.request({
url: '/admin/ad/sort/add',
method: 'POST',
data,
});
}
/**
* @description: 更新
*/
export function adSortUpdate(data: any) {
return http.request({
url: '/admin/ad/sort/update',
method: 'PUT',
data,
});
}
/**
* @description: 删除
*/
export function adSortDelete(adSortId) {
return http.request({
url: '/admin/ad/sort/delete/' + adSortId,
method: 'DELETE',
});
}
/**
* @description: 批量删除
*/
export function adSortBatchDelete(data: any) {
return http.request({
url: '/admin/ad/sort/batchDelete',
method: 'DELETE',
data,
});
}

View File

@ -1,58 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 缓存名称列表
*/
export function getCacheNames(params?) {
return http.request({
url: '/cache/getNames',
method: 'GET',
params,
});
}
/**
* @description: 缓存key列表
*/
export function getCacheKeys(cacheName) {
return http.request({
url: '/cache/getKeys/'+cacheName,
method: 'get',
});
}
/**
* @description: 缓存value列表
*/
export function getCacheValue(params?) {
return http.request({
url: '/cache/getValue',
method: 'get',
params
});
}
/**
* @description: 删除缓存名称
*/
export function deleteCacheName(cacheName) {
return http.request({
url: '/cache/deleteCacheName/'+cacheName,
method: 'DELETE',
});
}
/**
* @description: 删除缓存key
*/
export function deleteCacheKey(cacheKey) {
return http.request({
url: '/cache/deleteCacheKey/'+cacheKey,
method: 'DELETE',
});
}
/**
* @description: 清理全部
*/
export function deleteCacheAll() {
return http.request({
url: '/cache/deleteCacheAll',
method: 'DELETE',
});
}

View File

@ -1,119 +0,0 @@
<template>
<a-modal
v-model:visible="props.visible"
:title="props.positionId ? '编辑' : '新增'"
width="500px"
@cancel="dialogClose"
>
<a-form
class="ls-form"
ref="formRef"
:model="formData"
:label-col="{ style: { width: '85px' } }"
>
<a-form-item
label="岗位名称"
name="name"
:rules="{ required: true, message: '请输入岗位名称', trigger: 'blur' }"
>
<a-input v-model:value="formData.name" placeholder="请输入岗位名称" allow-clear />
</a-form-item>
<a-form-item label="岗位状态" name="code">
<a-radio-group v-model:value="formData.status" name="status">
<a-radio :value="1">正常</a-radio>
<a-radio :value="2">停用</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="排序" name="sort">
<a-input-number v-model:value="formData.sort" />
</a-form-item>
</a-form>
<template #footer>
<span class="dialog-footer">
<a-button @click="dialogClose">取消</a-button>
<a-button :loading="subLoading" type="primary" @click="submit"> 确定 </a-button>
</span>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'ant-design-vue';
import { getPositionDetail, positionAdd, positionUpdate } from '@/api/system/position';
import { onMounted, reactive, shallowRef } from 'vue';
import { message } from 'ant-design-vue';
import { useLockFn } from '@/utils/useLockFn';
/**
* 定义参数变量
*/
const emit = defineEmits(['success', 'update:visible']);
const formRef = shallowRef<FormInstance>();
/**
* 定义表单参数
*/
const formData = reactive({
id: '',
name: '',
status: 1,
sort: 0,
});
/**
* 定义接收的参数
*/
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
positionId: {
type: Number,
required: true,
default: 0,
},
});
/**
* 执行提交表单
*/
const handleSubmit = async () => {
await formRef.value?.validate();
props.positionId ? await positionUpdate(formData) : await positionAdd(formData);
message.success('操作成功');
emit('update:visible', false);
emit('success');
};
/**
* 关闭窗体
*/
const dialogClose = () => {
emit('update:visible', false);
};
const { isLock: subLoading, lockFn: submit } = useLockFn(handleSubmit);
/**
* 设置表单数据
*/
const setFormData = async () => {
const data = await getPositionDetail(props.positionId);
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key];
}
}
};
/**
* 钩子函数
*/
onMounted(() => {
if (props.positionId) {
setFormData();
}
});
</script>

View File

@ -1,67 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 参数列表
*/
export function getParamList(params?) {
return http.request({
url: '/param/page',
method: 'GET',
params,
});
}
export function getParamAllList(params?) {
return http.request({
url: '/param/list',
method: 'GET',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getParamDetail(paramId) {
return http.request({
url: '/param/detail/'+paramId,
method: 'get',
});
}
/**
* @description: 添加参数
*/
export function paramAdd(data:any) {
return http.request({
url: '/param/add',
method: 'POST',
data,
});
}
/**
* @description: 更新参数
*/
export function paramUpdate(data:any) {
return http.request({
url: '/param/update',
method: 'PUT',
data
});
}
/**
* @description: 删除参数
*/
export function paramDelete(paramId) {
return http.request({
url: '/param/delete/'+paramId,
method: 'DELETE',
});
}
/**
* @description: 批量删除参数
*/
export function paramBatchDelete(data:any) {
return http.request({
url: '/param/batchDelete',
method: 'DELETE',
data
});
}

View File

@ -1,172 +0,0 @@
<template>
<a-modal
v-model:visible="props.visible"
:title="props.linkId ? '编辑' : '新增'"
width="500px"
@cancel="dialogClose"
>
<a-form
class="ls-form"
ref="formRef"
:model="formData"
:label-col="{ style: { width: '85px' } }"
>
<a-form-item
label="名称"
name="name"
:rules="{ required: true, message: '请输入名称', trigger: 'blur' }"
>
<a-input
class="ls-input"
v-model:value="formData.name"
placeholder="请输入名称"
clearable
/>
</a-form-item>
<a-form-item
label="类型"
name="type"
:rules="{ required: true, message: '请选择类型', trigger: 'change' }"
>
<a-select v-model:value="formData.type" placeholder="请选择类型">
<a-select-option :value="1">友情链接</a-select-option>
<a-select-option :value="2">合作伙伴</a-select-option>
</a-select>
</a-form-item>
<a-form-item
label="地址"
name="url"
:rules="{ required: true, message: '请输入地址', trigger: 'blur' }"
>
<a-input v-model:value="formData.url" placeholder="请输入地址" />
</a-form-item>
<a-form-item
label="形式"
name="form"
:rules="{ required: true, message: '请选择形式', trigger: 'change' }"
>
<a-select v-model:value="formData.form" placeholder="请选择形式">
<a-select-option :value="1">文字链接</a-select-option>
<a-select-option :value="2">图片链接</a-select-option>
</a-select>
</a-form-item>
<a-form-item
label="图片"
name="image"
:rules="{ required: true, message: '请上传图片', trigger: 'change' }"
v-if="formData.form == 2"
>
<UploadImg
@change-file-name="(name) => (formData.coverImgName = name)"
:fileType="['image/jpeg', 'image/png', 'image/jpg', 'image/gif']"
name="article"
:fileSize="200"
v-model:image-url="formData.image"
>
<template #tip>支持扩展名: jpg png jpeg;文件大小不超过200M</template>
</UploadImg>
</a-form-item>
<a-form-item label="排序" name="sort">
<a-input-number v-model:value="formData.sort" />
</a-form-item>
<a-form-item label="状态">
<a-radio-group v-model:value="formData.status" name="status">
<a-radio :value="1">在用</a-radio>
<a-radio :value="2">停用</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
<template #footer>
<span class="dialog-footer">
<a-button @click="dialogClose">取消</a-button>
<a-button :loading="subLoading" type="primary" @click="submit"> 确定 </a-button>
</span>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'ant-design-vue';
import { getLinkDetail, linkAdd, linkUpdate } from '@/api/content/link';
import { onMounted, reactive, shallowRef } from 'vue';
import { message } from 'ant-design-vue';
import { useLockFn } from '@/utils/useLockFn';
import UploadImg from '@/components/Upload/Image.vue';
/**
* 定义参数变量
*/
const emit = defineEmits(['success', 'update:visible']);
const formRef = shallowRef<FormInstance>();
/**
* 定义表单参数
*/
const formData = reactive({
id: '',
name: '',
type: undefined,
url: '',
form: undefined,
image: '',
status: 1,
sort: 0,
});
/**
* 定义接收的参数
*/
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
linkId: {
type: Number,
required: true,
default: 0,
},
});
/**
* 执行提交
*/
const handleSubmit = async () => {
await formRef.value?.validate();
props.linkId ? await linkUpdate(formData) : await linkAdd(formData);
message.success('操作成功');
emit('update:visible', false);
emit('success');
};
/**
* 关闭窗体
*/
const dialogClose = () => {
emit('update:visible', false);
};
const { isLock: subLoading, lockFn: submit } = useLockFn(handleSubmit);
/**
* 设置表单数据
*/
const setFormData = async () => {
const data = await getLinkDetail(props.linkId);
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key];
}
}
};
/**
* 钩子函数
*/
onMounted(() => {
if (props.linkId) {
setFormData();
}
});
</script>

View File

@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1631453917190" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1531" width="32" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><style type="text/css"></style></defs><path d="M300.032 558.08V427.52c0-19.968 13.312-35.84 29.696-35.84s29.696 15.872 29.696 35.84V558.08c0 19.968-13.312 35.84-29.696 35.84s-29.696-15.872-29.696-35.84zM480.256 558.08V363.52c0-19.968 13.312-35.84 29.696-35.84 16.384 0 29.696 15.872 29.696 35.84v194.56c0 19.968-13.312 35.84-29.696 35.84-16.384 0-29.696-15.872-29.696-35.84zM660.48 558.08V299.52c0-19.968 13.312-35.84 29.696-35.84s29.696 15.872 29.696 35.84V558.08c0 19.968-13.312 35.84-29.696 35.84s-29.696-15.872-29.696-35.84z" p-id="1532" fill="#2d8cf0"></path><path d="M861.696 781.312H568.32v117.248h146.944c16.384 0 29.184 13.312 29.184 29.184 0 16.384-13.312 29.184-29.184 29.184H362.496c-16.384-1.024-28.672-14.848-27.648-30.72 1.024-14.848 12.8-27.136 27.648-27.648h146.944v-117.248H157.184c-65.024 0-117.248-52.736-117.248-117.248V194.048C39.936 129.024 92.16 76.8 157.184 76.8h704.512c65.024 0 117.248 52.736 117.248 117.248v470.016c0.512 64.512-52.224 117.248-117.248 117.248z m58.88-587.264c0-32.256-26.112-58.88-58.88-58.88H157.184c-32.256 0-58.88 26.112-58.88 58.88v470.016c0 32.256 26.112 58.88 58.88 58.88h704.512c32.256 0 58.88-26.112 58.88-58.88V194.048z" p-id="1533" fill="#2d8cf0"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,241 +0,0 @@
import { http } from '@/utils/http/axios';
export interface BasicResponseModel<T = any> {
code: number;
msg: string;
data: T;
}
export interface BasicPageParams {
pageNo: number;
pageSize: number;
total: number;
}
/**
* @description: 获取用户信息
*/
export function getUserInfo() {
return http.request({
url: '/index/getUser',
method: 'get',
});
}
/**
* @description: 用户登录
*/
export function login(params) {
return http.request<BasicResponseModel>(
{
url: '/login',
method: 'POST',
params,
},
{
isTransformResponse: false,
},
);
}
/**
* 统一认证登录
* @param data 参数
* @returns 返回结果
*/
export function login2(data) {
const formData = new FormData();
formData.append('username', data.username);
formData.append('password', data.password);
formData.append('code', data.code);
formData.append('grant_type', data.grant_type);
return http.request<BasicResponseModel>(
{
url: '/auth/oauth2/token',
method: 'POST',
data: formData,
headers: {
'Content-Type': 'multipart/form-data',
Authorization: 'Basic YWRtaW46MTIzNDU2',
},
},
{
isTransformResponse: false,
},
);
}
/**
* @description: 用户登录
*/
export function getInfoCaptcha() {
return http.request({
url: '/captcha',
method: 'GET',
});
}
/**
* @description: 用户修改密码
*/
export function changePassword(data) {
return http.request({
url: `/index/updatePassword`,
method: 'PUT',
data,
});
}
/**
* @description: 获取短信验证码
*/
export function sendSms(data) {
return http.request({
url: `/sms/sendSms`,
method: 'POST',
data,
});
}
/**
* @description: 用户登出
*/
export function logout(params) {
return http.request({
url: '/login/logout',
method: 'POST',
params,
});
}
/**
* @description: 获取用户列表
*/
export function getUserList(params) {
return http.request({
url: '/user/page',
method: 'get',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getUserDetail(userId) {
return http.request({
url: '/user/detail/' + userId,
method: 'get',
});
}
/**
* @description: 添加用户
*/
export function userAdd(data: any) {
return http.request({
url: '/user/add',
method: 'POST',
data,
});
}
/**
* @description: 更新用户
*/
export function userUpdate(data: any) {
return http.request({
url: '/user/update',
method: 'PUT',
data,
});
}
/**
* @description: 重置密码
*/
export function resetPwd(data: any) {
return http.request({
url: '/user/resetPwd',
method: 'PUT',
data,
});
}
/**
* @description: 删除用户
*/
export function userDelete(userId) {
return http.request({
url: '/user/delete/' + userId,
method: 'DELETE',
});
}
/**
* @description: 批量删除用户
*/
export function userBatchDelete(data: any) {
return http.request({
url: '/user/batchDelete',
method: 'DELETE',
data,
});
}
/**
* @description: 导入用户
*/
export function userImport(data) {
return http.request({
url: '/user/import',
method: 'POST',
data,
});
}
/**
* @description: 导出用户
*/
export function userExport() {
return http.request(
{
url: '/user/export',
method: 'GET',
responseType: 'blob',
},
{
isTransformResponse: false,
},
);
}
/**
* @description: 下载模板
*/
export function getTemplateByCode(code: any) {
return http.request({
url: '/file/template/getTemplateByCode/' + code,
method: 'GET',
});
}
/**
* @description: 获取打印地址
*/
export function getUserDocument(userId: any) {
return http.request({
url: '/user/document/' + userId,
method: 'GET',
});
}
/**
* @description: 城市列表
*/
export function getCityByList(pid: any) {
return http.request({
url: '/city/getCityList/' + pid,
method: 'get',
});
}

View File

@ -1,34 +0,0 @@
import { FormSchema } from '@/components/Form/index';
export const schemas: FormSchema[] = [
{
name: 'title',
component: 'Input',
label: '模板名称',
componentProps: {
placeholder: '请输入模板名称',
},
},
{
name: 'type',
component: 'Select',
label: '邮件类型',
componentProps: {
placeholder: '请选择邮件类型',
clearable: true,
options: [
{
label: '普通邮件',
value: '1',
},
{
label: '图文邮件',
value: '2',
},
{
label: '模板文件',
value: '3',
},
],
},
},
];

View File

@ -1,17 +0,0 @@
import { h } from 'vue';
import { ElTag } from 'element-plus';
export const columns = [
{
title: 'ID',
dataIndex: 'id',
},
{
title: '字典名称',
dataIndex: 'name',
},
{
title: '字典编码',
dataIndex: 'code',
},
];

View File

@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1631454216260" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2219" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><defs><style type="text/css"></style></defs><path d="M697.652 256c-23.565 0-42.667-19.103-42.667-42.667s19.102-42.666 42.667-42.666h124.651c40.288 0 73.697 31.956 73.697 72.347v85.783c0 23.564-19.103 42.667-42.667 42.667s-42.666-19.103-42.666-42.667V256H697.652z m113.015 597.333V496.565c0-23.564 19.102-42.666 42.666-42.666C876.897 453.899 896 473 896 496.565V866.32c0 40.391-33.41 72.348-73.697 72.348H201.697c-40.288 0-73.697-31.957-73.697-72.348V243.014c0-40.39 33.41-72.347 73.697-72.347h124.727c23.564 0 42.667 19.102 42.667 42.666 0 23.564-19.103 42.667-42.667 42.667h-113.09v597.333h597.333zM368.485 541.418c-23.564 0-42.667-19.102-42.667-42.666 0-23.564 19.103-42.667 42.667-42.667h320c23.564 0 42.667 19.103 42.667 42.667s-19.103 42.666-42.667 42.666h-320z m58.182-370.751c-23.564 0-42.667 19.102-42.667 42.666C384 236.897 403.103 256 426.667 256h170.666C620.897 256 640 236.897 640 213.333s-19.103-42.666-42.667-42.666H426.667z m0-85.334h170.666c70.693 0 128 57.308 128 128 0 70.693-57.307 128-128 128H426.667c-70.693 0-128-57.307-128-128 0-70.692 57.307-128 128-128zM368.485 696.57c-23.564 0-42.667-19.103-42.667-42.667s19.103-42.666 42.667-42.666h320c23.564 0 42.667 19.102 42.667 42.666 0 23.564-19.103 42.667-42.667 42.667h-320z" p-id="2220" fill="#f49776"></path></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -1,39 +0,0 @@
import type { QRCodeSegment, QRCodeRenderersOptions } from 'qrcode';
import { Fn } from '/#/index';
export type ContentType = string | QRCodeSegment[];
export type { QRCodeRenderersOptions };
export type LogoType = {
src: string;
logoSize: number;
borderColor: string;
bgColor: string;
borderSize: number;
crossOrigin: string;
borderRadius: number;
logoRadius: number;
};
export interface RenderQrCodeParams {
canvas: any;
content: ContentType;
width?: number;
options?: QRCodeRenderersOptions;
logo?: LogoType | string;
image?: HTMLImageElement;
downloadName?: string;
download?: boolean | Fn;
}
export type ToCanvasFn = (options: RenderQrCodeParams) => Promise<unknown>;
export interface QrCodeActionType {
download: (fileName?: string) => void;
}
export interface QrcodeDoneEventParams {
url: string;
ctx?: CanvasRenderingContext2D | null;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 528 KiB

View File

@ -1,165 +0,0 @@
import { upperFirst } from 'lodash-es';
export interface ViewportOffsetResult {
left: number;
top: number;
right: number;
bottom: number;
rightIncludeBody: number;
bottomIncludeBody: number;
}
export function getBoundingClientRect(element: Element): DOMRect | number {
if (!element || !element.getBoundingClientRect) {
return 0;
}
return element.getBoundingClientRect();
}
function trim(string: string) {
return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '');
}
/* istanbul ignore next */
export function hasClass(el: Element, cls: string) {
if (!el || !cls) return false;
if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.');
if (el.classList) {
return el.classList.contains(cls);
} else {
return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1;
}
}
/* istanbul ignore next */
export function addClass(el: Element, cls: string) {
if (!el) return;
let curClass = el.className;
const classes = (cls || '').split(' ');
for (let i = 0, j = classes.length; i < j; i++) {
const clsName = classes[i];
if (!clsName) continue;
if (el.classList) {
el.classList.add(clsName);
} else if (!hasClass(el, clsName)) {
curClass += ' ' + clsName;
}
}
if (!el.classList) {
el.className = curClass;
}
}
/* istanbul ignore next */
export function removeClass(el: Element, cls: string) {
if (!el || !cls) return;
const classes = cls.split(' ');
let curClass = ' ' + el.className + ' ';
for (let i = 0, j = classes.length; i < j; i++) {
const clsName = classes[i];
if (!clsName) continue;
if (el.classList) {
el.classList.remove(clsName);
} else if (hasClass(el, clsName)) {
curClass = curClass.replace(' ' + clsName + ' ', ' ');
}
}
if (!el.classList) {
el.className = trim(curClass);
}
}
/**
* Get the left and top offset of the current element
* left: the distance between the leftmost element and the left side of the document
* top: the distance from the top of the element to the top of the document
* right: the distance from the far right of the element to the right of the document
* bottom: the distance from the bottom of the element to the bottom of the document
* rightIncludeBody: the distance between the leftmost element and the right side of the document
* bottomIncludeBody: the distance from the bottom of the element to the bottom of the document
*
* @description:
*/
export function getViewportOffset(element: Element): ViewportOffsetResult {
const doc = document.documentElement;
const docScrollLeft = doc.scrollLeft;
const docScrollTop = doc.scrollTop;
const docClientLeft = doc.clientLeft;
const docClientTop = doc.clientTop;
const pageXOffset = window.pageXOffset;
const pageYOffset = window.pageYOffset;
const box = getBoundingClientRect(element);
const { left: retLeft, top: rectTop, width: rectWidth, height: rectHeight } = box as DOMRect;
const scrollLeft = (pageXOffset || docScrollLeft) - (docClientLeft || 0);
const scrollTop = (pageYOffset || docScrollTop) - (docClientTop || 0);
const offsetLeft = retLeft + pageXOffset;
const offsetTop = rectTop + pageYOffset;
const left = offsetLeft - scrollLeft;
const top = offsetTop - scrollTop;
const clientWidth = window.document.documentElement.clientWidth;
const clientHeight = window.document.documentElement.clientHeight;
return {
left: left,
top: top,
right: clientWidth - rectWidth - left,
bottom: clientHeight - rectHeight - top,
rightIncludeBody: clientWidth - left,
bottomIncludeBody: clientHeight - top,
};
}
export function hackCss(attr: string, value: string) {
const prefix: string[] = ['webkit', 'Moz', 'ms', 'OT'];
const styleObj: any = {};
prefix.forEach((item) => {
styleObj[`${item}${upperFirst(attr)}`] = value;
});
return {
...styleObj,
[attr]: value,
};
}
/* istanbul ignore next */
export function on(
element: Element | HTMLElement | Document | Window,
event: string,
handler: EventListenerOrEventListenerObject,
): void {
if (element && event && handler) {
element.addEventListener(event, handler, false);
}
}
/* istanbul ignore next */
export function off(
element: Element | HTMLElement | Document | Window,
event: string,
handler: Fn,
): void {
if (element && event && handler) {
element.removeEventListener(event, handler, false);
}
}
/* istanbul ignore next */
export function once(el: HTMLElement, event: string, fn: EventListener): void {
const listener = function (this: any, ...args: unknown[]) {
if (fn) {
fn.apply(this, args);
}
off(el, event, listener);
};
on(el, event, listener);
}

View File

@ -1,53 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 消息列表
*/
export function getMessageList(params?) {
return http.request({
url: '/admin/message/page',
method: 'GET',
params,
});
}
/**
* @description: 已读消息
*/
export function messageRead(id) {
return http.request({
url: '/admin/message/read/' + id,
method: 'get',
});
}
/**
* @description: 根据ID获取详情
*/
export function getMessageDetail(id) {
return http.request({
url: '/admin/message/detail/' + id,
method: 'get',
});
}
/**
* @description: 删除消息
*/
export function messageDelete(id) {
return http.request({
url: '/admin/message/delete/' + id,
method: 'DELETE',
});
}
/**
* @description: 批量删除消息
*/
export function messageBatchDelete(data: any) {
return http.request({
url: '/admin/message/batchDelete',
method: 'DELETE',
data,
});
}

View File

@ -1,193 +0,0 @@
<template>
<a-modal
v-model:visible="props.visible"
:title="props.jobId ? '编辑' : '新增'"
width="600px"
@cancel="dialogClose"
>
<a-form
class="ls-form"
ref="formRef"
:model="formData"
:label-col="{ style: { width: '110px' } }"
>
<a-form-item
label="任务名称"
name="jobName"
:rules="{ required: true, message: '请输入任务名称', trigger: 'blur' }"
>
<a-input
class="ls-input"
v-model:value="formData.jobName"
placeholder="请输入任务名称"
allow-clear
/>
</a-form-item>
<a-form-item
label="任务别名"
name="jobAlias"
:rules="{ required: true, message: '请输入任务别名', trigger: 'blur' }"
>
<a-input
class="ls-input"
v-model:value="formData.jobAlias"
placeholder="请输入任务别名"
allow-clear
/>
</a-form-item>
<a-form-item
label="任务分组"
name="jobGroup"
:rules="{ required: true, message: '请输入任务分组', trigger: 'blur' }"
>
<a-select v-model:value="formData.jobGroup" placeholder="请选择任务分组">
<a-select-option value="DEFAULT">DEFAULT</a-select-option>
</a-select>
</a-form-item>
<a-form-item
label="任务触发器"
name="jobTrigger"
:rules="{ required: true, message: '请输入任务触发器', trigger: 'blur' }"
>
<a-input
class="ls-input"
v-model:value="formData.jobTrigger"
placeholder="请输入任务触发器"
allow-clear
/>
</a-form-item>
<a-form-item
label="任务状态"
name="status"
:rules="{ required: true, message: '请选择任务状态', trigger: 'blur' }"
>
<a-select v-model:value="formData.status" placeholder="请选择任务状态">
<a-select-option :value="0">未发布</a-select-option>
<a-select-option :value="1">运行中</a-select-option>
<a-select-option :value="2">暂停</a-select-option>
<a-select-option :value="3">删除</a-select-option>
</a-select>
</a-form-item>
<a-form-item
label="正则表达式"
name="cronExpression"
:rules="{ required: true, message: '请输入正则表达式', trigger: 'blur' }"
>
<a-input
class="ls-input"
v-model:value="formData.cronExpression"
placeholder="请输入正则表达式"
allow-clear
/>
</a-form-item>
<a-form-item
label="执行策略"
name="executePolicy"
:rules="{ required: true, message: '请选择执行策略', trigger: 'blur' }"
>
<a-select v-model:value="formData.executePolicy" placeholder="请选择执行策略">
<a-select-option :value="1">立即执行</a-select-option>
<a-select-option :value="2">执行一次</a-select-option>
<a-select-option :value="3">放弃执行</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="是否同步任务" name="isSync" class="flex-1">
<a-radio-group v-model:value="formData.isSync" name="isSync">
<a-radio :value="1">是</a-radio>
<a-radio :value="0">否</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item
label="任务URL"
name="url"
:rules="{ required: true, message: '请输入任务URL', trigger: 'blur' }"
>
<a-input
class="ls-input"
v-model:value="formData.url"
placeholder="请输入任务URL"
allow-clear
/>
</a-form-item>
<a-form-item
label="任务备注"
name="note"
:rules="{ required: true, message: '请输入任务备注', trigger: 'blur' }"
>
<a-input v-model:value="formData.note" type="textarea" />
</a-form-item>
</a-form>
<template #footer>
<span class="dialog-footer">
<a-button @click="dialogClose">取消</a-button>
<a-button :loading="subLoading" type="primary" @click="submit"> 确定 </a-button>
</span>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'element-plus';
import { getJobDetail, jobAdd, jobUpdate } from '@/api/monitor/job';
import { onMounted, reactive, shallowRef } from 'vue';
import { message } from 'ant-design-vue';
import { useLockFn } from '@/utils/useLockFn';
const emit = defineEmits(['success', 'update:visible']);
const formRef = shallowRef<FormInstance>();
const formData = reactive({
id: '',
jobName: '',
jobAlias: '',
jobGroup: '',
jobTrigger: '',
status: '',
cronExpression: '',
executePolicy: '',
isSync: 0,
url: '',
note: '',
});
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
jobId: {
type: Number,
required: true,
default: 0,
},
});
const handleSubmit = async () => {
await formRef.value?.validate();
props.jobId ? await jobUpdate(formData) : await jobAdd(formData);
message.success('操作成功');
emit('update:visible', false);
emit('success');
};
const dialogClose = () => {
emit('update:visible', false);
};
const { isLock: subLoading, lockFn: submit } = useLockFn(handleSubmit);
const setFormData = async () => {
const data = await getJobDetail(props.jobId);
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key];
}
}
};
onMounted(() => {
if (props.jobId) {
setFormData();
}
});
</script>

View File

@ -1,88 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 职级列表
*/
export function getLevelList(params?) {
return http.request({
url: '/admin/level/page',
method: 'GET',
params,
});
}
/**
* 获取全部职级列表
* @param params 参数
* @returns 返回结果
*/
export function getLevelAllList(params?) {
return http.request({
url: '/admin/level/list',
method: 'GET',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getLevelDetail(levelId) {
return http.request({
url: '/admin/level/detail/' + levelId,
method: 'get',
});
}
/**
* @description: 添加职级
*/
export function levelAdd(data: any) {
return http.request({
url: '/admin/level/add',
method: 'POST',
data,
});
}
/**
* @description: 更新职级
*/
export function levelUpdate(data: any) {
return http.request({
url: '/admin/level/update',
method: 'PUT',
data,
});
}
/**
* @description: 删除职级
*/
export function levelDelete(levelId) {
return http.request({
url: '/admin/level/delete/' + levelId,
method: 'DELETE',
});
}
/**
* @description: 批量删除职级
*/
export function levelBatchDelete(data: any) {
return http.request({
url: '/admin/level/batchDelete',
method: 'DELETE',
data,
});
}
/**
* @description: 导出职级
*/
export function levelExport() {
return http.request({
url: '/admin/level/export',
method: 'GET',
});
}

View File

@ -1,37 +0,0 @@
<template>
<a-list item-layout="horizontal" :data-source="listData" class="px-4">
<template #renderItem="{ item }">
<a-list-item>
<a-list-item-meta>
<template #title>
{{ item.title }}
</template>
<template #description>
{{ item.description }}<a-button type="link" class="ml-4">修改</a-button>
</template>
</a-list-item-meta>
</a-list-item>
</template>
</a-list>
</template>
<script lang="ts" setup>
const listData = [
{
title: '账户密码',
description: '绑定手机和邮箱,并设置密码,帐号更安全',
},
{
title: '绑定手机',
description: '已绑定手机号:+8618000000001',
},
{
title: '密保问题',
description: '未设置密保问题,密保问题可有效保护账户安全',
},
{
title: '个性域名',
description: '已绑定域名https://www.baidu.com',
},
];
</script>

View File

@ -1,15 +0,0 @@
import { isReactive, isRef } from 'vue';
function setLoading(loading, val) {
if (loading != undefined && isRef(loading)) {
loading.value = val;
} else if (loading != undefined && isReactive(loading)) {
loading.loading = val;
}
}
export const useAsync = async (func: Promise<any>, loading: any): Promise<any> => {
setLoading(loading, true);
return await func.finally(() => setLoading(loading, false));
};

View File

@ -1,224 +0,0 @@
<template>
<div class="menu-index">
<a-card :bordered="false" class="pt-3 mb-3 proCard">
<div>
<a-button type="primary" @click="handleAdd()" v-perm="['sys:city:add']">
<template #icon><PlusOutlined /></template>
新增
</a-button>
</div>
</a-card>
<a-card :bordered="false" class="pt-3 mb-3 proCard">
<a-table
border
v-loading="loading"
ref="tableRef"
:columns="columns"
:dataSource="lists"
@expand="getChild"
rowKey="areaCode"
>
<template #bodyCell="{ column, record, index }">
<template v-if="column.key == 'action'">
<a-space>
<a-button type="primary" @click="handleAdd(record)" v-perm="['sys:city:add']">
<template #icon><PlusOutlined /></template>
新增</a-button
>
<a-button type="primary" @click="handleEdit(record)" v-perm="['sys:city:update']">
<template #icon><EditOutlined /></template>
编辑
</a-button>
<a-button
type="primary"
danger
@click="handleDelete(record)"
v-perm="['sys:city:delete']"
>
<template #icon><DeleteOutlined /></template>
删除
</a-button>
</a-space>
</template>
</template>
</a-table>
</a-card>
<editDialog
ref="editRef"
v-if="editVisible"
:cityId="cityId"
:parentData="parentData"
:itemData="itemData"
v-model:visible="editVisible"
@success="refreshDataList"
/>
</div>
</template>
<script lang="ts" setup name="menu">
import { defineAsyncComponent, nextTick, onMounted, ref, shallowRef } from 'vue';
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons-vue';
import { cityDelete } from '@/api/data/city';
import { getCityByList } from '@/api/system/user';
import { columns } from './columns';
import { Modal, message } from 'ant-design-vue';
/**
* 导入组件
*/
const editDialog = defineAsyncComponent(() => import('./edit.vue'));
/**
* 定义参数变量
*/
const tableRef = ref();
const loading = ref(false);
const editVisible = ref(false);
const cityId = ref(0);
const parentData = ref();
const itemData = ref({});
const lists = ref([]);
const maps = ref(new Map());
/**
* 获取行政区划列表
* @param code 参数
*/
const getDataList = async (code: any) => {
try {
loading.value = true;
let res = await getCityByList(code);
let data = res.length > 0 ? res : [];
data.map((item) => {
item.children = [];
});
lists.value = data;
} catch (e) {
lists.value = [];
} finally {
loading.value = false;
}
};
/**
* 刷新数据列表
*/
const refreshDataList = (code) => {
console.log(code);
if (code == 0 || Object.keys(code).length === 0) {
getDataList(0);
} else {
console.log(code);
getChild(true, code);
}
};
/**
* 执行添加
* @param data 参数
*/
const handleAdd = async (data: any) => {
cityId.value = 0;
if (data) {
itemData.value = data;
let datas = findParentNode(lists.value, data.pid);
if (datas) {
parentData.value = datas;
} else {
parentData.value = data;
}
}
await nextTick();
editVisible.value = true;
};
/**
* 执行编辑
* @param data 参数
*/
const handleEdit = async (data: any) => {
cityId.value = data.id;
parentData.value = findParentNode(lists.value, data.pid);
await nextTick();
editVisible.value = true;
};
/**
* 执行删除
* @param row 参数
*/
const handleDelete = async (row: any) => {
console.log(row);
Modal.confirm({
title: '提示',
content: '确定要删除?',
onOk: async () => {
loading.value = true;
await cityDelete(row.id);
message.success('删除成功');
refreshDataList({ areaCode: row.parentCode });
loading.value = false;
},
});
};
/**
* 表格点击获取子级
* @param expanded 是否展开
* @param record 记录
*/
const getChild = async (expanded, record) => {
console.log(record);
if (expanded) {
let res = await getCityByList(record.areaCode);
const data = lists.value;
const children = res;
children.forEach((item) => {
if (item.level < 4) {
item.children = [];
}
});
const dataSourceMap = (items) => {
items.find((item) => {
if (item.areaCode === record.areaCode) {
item.children = children;
return items;
}
if (item.children && item.children.length > 0) {
dataSourceMap(item.children);
}
});
};
dataSourceMap(data);
lists.value = [...lists.value];
}
};
/**
* 根据子节点找到父节点
* @param nodes 节点
* @param targetId 目标节点ID
*/
const findParentNode = (nodes, targetId) => {
for (let node of nodes) {
if (node.id == targetId) {
return node;
}
if (node.children && node.children.length > 0) {
const result = findParentNode(node.children, targetId);
if (result) {
return node;
}
}
}
};
/**
* 钩子函数
*/
onMounted(() => {
getDataList(0);
});
</script>
<style scoped></style>

View File

@ -1,109 +0,0 @@
<template>
<a-modal v-model:visible="props.visible" :title="props.dictId ? '编辑' : '新增'" width="500px" @cancel="dialogClose">
<a-form
class="ls-form"
ref="formRef"
:model="formData"
:label-col="{ style: { width: '80px' }}">
<a-form-item
label="字典名称"
name="name"
:rules="{ required: true, message: '请输入字典名称', trigger: 'blur' }"
>
<a-input
v-model:value="formData.name"
placeholder="请输入字典名称"
allow-clear
/>
</a-form-item>
<a-form-item
label="字典编码"
name="code"
:rules="{ required: true, message: '请输入字典编码', trigger: 'blur' }"
>
<a-input
v-model:value="formData.code"
:disabled="props.dictId"
placeholder="请输入字典编码"
allow-clear
/>
</a-form-item>
<a-form-item label="排序" name="sort">
<a-input-number v-model:value="formData.sort"/>
</a-form-item>
<a-form-item label="备注" name="note">
<a-input v-model:value="formData.note" type="textarea" placeholder="请输入备注" allow-clear />
</a-form-item>
</a-form>
<template #footer>
<span class="dialog-footer">
<a-button @click="dialogClose">取消</a-button>
<a-button :loading="subLoading" type="primary" @click="submit">
确定
</a-button>
</span>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'ant-design-vue';
import {dictAdd,dictUpdate,getDictDetail} from "@/api/data/dictionary";
import {onMounted, reactive, shallowRef} from "vue";
import { message } from 'ant-design-vue'
import {useLockFn} from "@/utils/useLockFn";
const emit = defineEmits(["success", "update:visible"]);
const formRef = shallowRef<FormInstance>();
const formData = reactive({
id: "",
name: "",
code: "",
sort: 0,
note:'',
});
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false
},
dictId: {
type: Number,
required: true,
default: 0
}
});
const handleSubmit = async () => {
await formRef.value?.validate();
props.dictId ? await dictUpdate(formData) : await dictAdd(formData);
message.success("操作成功");
emit("update:visible", false);
emit("success");
};
const dialogClose = () => {
emit("update:visible", false);
};
const { isLock:subLoading,lockFn: submit } = useLockFn(handleSubmit);
const setFormData = async () => {
const data = await getDictDetail(props.dictId);
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key];
}
}
};
onMounted(() => {
if (props.dictId) {
setFormData();
}
});
</script>

View File

@ -1,145 +0,0 @@
{
"name": "naive-admin-antd",
"version": "1.4.1",
"author": {
"name": "Ahjung",
"email": "735878602@qq.com"
},
"private": true,
"scripts": {
"bootstrap": "pnpm install",
"serve": "pnpm run dev",
"dev": "vite",
"build": "cross-env NODE_ENV=production vite build && esno ./build/script/postBuild.ts",
"build:test": "cross-env vite build --mode test && esno ./build/script/postBuild.ts",
"build:no-cache": "pnpm clean:cache && pnpm run build",
"report": "cross-env REPORT=true pnpm run build",
"type:check": "vue-tsc --noEmit --skipLibCheck",
"preview": "pnpm run build && vite preview",
"preview:dist": "vite preview",
"clean:cache": "rimraf node_modules/.cache/ && rimraf node_modules/.vite",
"clean:lib": "rimraf node_modules",
"lint:eslint": "eslint \"{src,mock}/**/*.{vue,ts,tsx}\" --fix",
"lint:prettier": "prettier --write --loglevel warn \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
"lint:stylelint": "stylelint --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
"lint:lint-staged": "lint-staged -c ./.husky/lintstagedrc.js",
"lint:pretty": "pretty-quick --staged",
"test prod gzip": "http-server dist --cors --gzip -c-1",
"reinstall": "rimraf pnpm-lock.yaml && rimraf package.lock.json && rimraf node_modules && pnpm run bootstrap",
"build typecheck": "vuedx-typecheck . && vite build",
"deploy": "gh-pages -d dist"
},
"dependencies": {
"@ant-design-vue/pro-layout": "^3.2.5",
"@ant-design/icons-vue": "^6.1.0",
"@tinymce/tinymce-vue": "^5.1.1",
"tinymce": "5.10.3",
"@vueup/vue-quill": "1.0.0-beta.8",
"@vueuse/core": "^8.9.4",
"ant-design-vue": "3.2.20",
"axios": "^0.27.2",
"cropperjs": "^1.6.2",
"dayjs": "^1.11.11",
"echarts": "^5.5.1",
"lodash-es": "^4.17.21",
"mockjs": "^1.1.0",
"moment": "^2.30.1",
"nprogress": "^0.2.0",
"perfect-scrollbar": "^1.5.5",
"pinia": "^2.1.7",
"print-js": "^1.6.0",
"qrcode": "^1.5.3",
"qs": "^6.12.2",
"vue": "3.3.4",
"vue-router": "^4.4.0",
"vue-types": "^4.2.1",
"vue-cropper": "0.5.8",
"vuedraggable": "^4.1.0",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@commitlint/cli": "^17.8.1",
"@commitlint/config-conventional": "^17.8.1",
"@types/element-resize-detector": "^1.1.6",
"@types/lodash-es": "^4.17.12",
"@types/node": "^17.0.45",
"@types/qrcode": "^1.5.5",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
"@vitejs/plugin-vue": "^2.3.4",
"@vitejs/plugin-vue-jsx": "^1.3.10",
"@vue/compiler-sfc": "^3.4.31",
"@zougt/some-loader-utils": "^1.4.3",
"@zougt/vite-plugin-theme-preprocessor": "^1.4.8",
"autoprefixer": "^10.4.19",
"color": "^4.2.3",
"colors": "^1.4.0",
"commitizen": "^4.3.0",
"core-js": "^3.37.1",
"cross-env": "^7.0.3",
"dotenv": "^16.4.5",
"eslint": "^8.57.0",
"eslint-config-prettier": "^8.10.0",
"eslint-define-config": "^1.24.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.27.0",
"esno": "^0.16.3",
"fs-extra": "^10.1.0",
"gh-pages": "^4.0.0",
"husky": "^8.0.3",
"install": "^0.13.0",
"less": "^4.2.0",
"less-loader": "^11.1.4",
"lint-staged": "^12.5.0",
"pnpm": "^7.33.7",
"postcss": "^8.4.39",
"prettier": "^2.8.8",
"pretty-quick": "^3.3.1",
"rimraf": "^3.0.2",
"rollup-plugin-visualizer": "^5.12.0",
"stylelint": "^14.16.1",
"stylelint-config-prettier": "^9.0.5",
"stylelint-config-standard": "^25.0.0",
"stylelint-order": "^5.0.0",
"stylelint-scss": "^4.7.0",
"ts-node": "^10.9.2",
"typescript": "^4.9.5",
"unplugin-vue-components": "^0.19.9",
"vite": "^5.3.3",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-html": "^3.2.2",
"vite-plugin-mock": "^2.9.8",
"vite-plugin-windicss": "^1.9.3",
"vue-eslint-parser": "^9.4.3",
"vue-tsc": "^0.34.17"
},
"lint-staged": {
"*.{vue,js,ts,tsx}": "eslint --fix"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-customizable"
}
},
"keywords": [
"vue",
"antd-admin",
"antd-admin-pro",
"vue3",
"ts",
"tsx",
"admin",
"typescript"
],
"engines": {
"node": ">= 16.9.0"
},
"pnpm": {
"peerDependencyRules": {
"ignoreMissing": [
"rollup",
"webpack"
]
}
}
}

View File

@ -1,40 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 文件日志列表
*/
export function getFileLogList(params?) {
return http.request({
url: '/file/log/page',
method: 'GET',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getFileLogDetail(id) {
return http.request({
url: '/file/log/detail/' + id,
method: 'get',
});
}
/**
* @description: 删除文件日志
*/
export function fileLogDelete(id) {
return http.request({
url: '/file/log/delete/' + id,
method: 'DELETE',
});
}
/**
* @description: 批量删除文件日志
*/
export function fileLogBatchDelete(data: any) {
return http.request({
url: '/file/log/batchDelete',
method: 'DELETE',
data,
});
}

File diff suppressed because one or more lines are too long

View File

@ -1,23 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 获取字典列表
*/
export function getDictionary(params?) {
return http.request({
url: '/dictionary/list',
method: 'get',
params,
});
}
/**
* @description: 获取字典详情
*/
export function getDictionaryInfo(params) {
return http.request({
url: '/dictionary/info',
method: 'get',
params,
});
}

View File

@ -1,43 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 操作日志列表
*/
export function getOperLogList(params?) {
return http.request({
url: '/oper/log/page',
method: 'GET',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getOperLogDetail(id) {
return http.request({
url: '/oper/log/detail/' + id,
method: 'get',
});
}
/**
* @description: 删除操作日志
*/
export function operLogDelete(id) {
return http.request({
url: '/oper/log/delete/' + id,
method: 'DELETE',
});
}
/**
* @description: 批量删除操作日志
*/
export function operLogBatchDelete(data: any) {
return http.request({
url: '/oper/log/batchDelete',
method: 'DELETE',
data,
});
}

View File

@ -1,7 +0,0 @@
import { App } from 'vue';
/**
* 注册全局方法 待完善
* @param app
*/
export function setupGlobalMethods(app: App) {}

View File

@ -1,67 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 岗位列表
*/
export function getPositionList(params?) {
return http.request({
url: '/position/page',
method: 'GET',
params,
});
}
export function getPositionAllList(params?) {
return http.request({
url: '/position/list',
method: 'GET',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getPositionDetail(positionId) {
return http.request({
url: '/position/detail/'+positionId,
method: 'get',
});
}
/**
* @description: 添加岗位
*/
export function positionAdd(data:any) {
return http.request({
url: '/position/add',
method: 'POST',
data,
});
}
/**
* @description: 更新岗位
*/
export function positionUpdate(data:any) {
return http.request({
url: '/position/update',
method: 'PUT',
data
});
}
/**
* @description: 删除岗位
*/
export function positionDelete(positionId) {
return http.request({
url: '/position/delete/'+positionId,
method: 'DELETE',
});
}
/**
* @description: 批量删除岗位
*/
export function positionBatchDelete(data:any) {
return http.request({
url: '/position/batchDelete',
method: 'DELETE',
data
});
}

View File

@ -1,253 +0,0 @@
<template>
<PageWrapper>
<a-card :bordered="false" class="pt-3 mb-3 proCard">
<BasicForm @register="register" @submit="handleSubmit" @reset="handleReset">
<template #statusSlot="{ model, field }">
<a-input v-model="model[field]" />
</template>
</BasicForm>
</a-card>
<a-card :bordered="false" class="proCard">
<BasicTable
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
ref="tableRef"
scroll-x="1200"
:row-selection="{ onChange: onSelectionChange }"
virtual-scroll
>
<template #tableTitle>
<a-space>
<a-button type="primary" @click="addUser" v-perm="['sys:user:add']">
<template #icon>
<PlusOutlined />
</template>
新建
</a-button>
<a-button
type="danger"
@click="handleDelete()"
:disabled="!selectionData.length"
v-perm="['sys:user:batchDelete']"
>
<template #icon>
<DeleteOutlined />
</template>
删除
</a-button>
<a-button type="primary" @click="importVisible = true" v-perm="['sys:user:import']">
<template #icon>
<UploadOutlined />
</template>
导入
</a-button>
<!-- <a-upload
ref="upload"
action="/api/user/import"
:headers="uploadHeaders"
:on-error="onError"
:on-success="onSuccess"
:before-upload="beforeUpload"
:show-file-list="false"
:limit="1"
v-perm="['sys:user:import']"
>
<a-button type="primary">
<template #icon>
<a-icon class="a-input__icon">
<Upload />
</a-icon>
</template>
导入
</a-button>
</a-upload> -->
<a-button
type="primary"
@click="handleExport"
:loading="exportLoading"
:disabled="exportLoading"
v-perm="['sys:user:export']"
>
<template #icon>
<DownloadOutlined />
</template>
导出
</a-button>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<a-space>
<a-button type="primary" @click="handleEdit(record.id)" v-perm="['sys:user:update']">
<template #icon><EditOutlined /></template>
编辑
</a-button>
<a-button
type="primary"
danger
@click="handleDelete(record.id)"
v-perm="['sys:user:delete']"
>
<template #icon><DeleteOutlined /></template>
删除
</a-button>
<a-button
type="primary"
v-if="record.type !== 1"
@click="handleResetPassWord(record.id)"
v-perm="['sys:user:resetPwd']"
>
<template #icon><PlusOutlined /></template>
重置密码</a-button
>
<a-button type="primary" @click="handlePrint(record.id)">
<template #icon><PrinterOutlined /></template>
打印</a-button
>
</a-space>
</template>
</template>
</BasicTable>
</a-card>
<editDialog
v-if="editVisible"
:userId="userId"
v-model:visible="editVisible"
@success="reloadTable('noRefresh')"
/>
<userUpload v-if="importVisible" v-model:visible="importVisible" @success="reloadTable()" />
</PageWrapper>
</template>
<script lang="ts" setup>
import { nextTick, reactive, ref, defineAsyncComponent } from 'vue';
import {
PlusOutlined,
EditOutlined,
DeleteOutlined,
DownloadOutlined,
UploadOutlined,
PrinterOutlined,
} from '@ant-design/icons-vue';
import { useForm } from '@/components/Form/index';
import {
getUserList,
userDelete,
userBatchDelete,
userExport,
resetPwd,
getUserDocument,
} from '@/api/system/user';
import { columns } from './columns';
import { schemas } from './querySchemas';
import { downloadByData } from '@/utils/file/download';
import { Modal, message } from 'ant-design-vue';
import printJS from 'print-js';
const userId = ref(0);
const tableRef = ref();
const editVisible = ref(false);
const importVisible = ref(false);
const selectionData = ref([]);
const exportLoading = ref(false);
const editDialog = defineAsyncComponent(() => import('./edit.vue'));
const userUpload = defineAsyncComponent(() => import('./userUpload.vue'));
const formParams = reactive({
realname: '',
role: '',
status: '',
});
const loadDataTable = async (res) => {
const result = await getUserList({ ...formParams, ...res });
return result;
};
function reloadTable(noRefresh = '') {
tableRef.value.reload(noRefresh ? {} : { pageNo: 1 });
}
async function handleEdit(id) {
userId.value = id;
await nextTick();
editVisible.value = true;
}
async function handleResetPassWord(id) {
Modal.confirm({
title: '提示',
content: '确定重置密码?',
onOk: async () => {
await resetPwd({ userId: id });
message.success('重置成功');
},
});
}
async function handleDelete(id) {
Modal.confirm({
title: '提示',
content: '确定要删除?',
onOk: async () => {
id ? await userDelete(id) : await userBatchDelete(selectionData.value);
message.success('删除成功');
reloadTable();
},
});
}
function handleSubmit(values) {
for (const key in formParams) {
formParams[key] = '';
}
for (const key in values) {
formParams[key] = values[key];
}
reloadTable();
}
function handleReset() {
for (const key in formParams) {
formParams[key] = '';
}
reloadTable();
}
function onSelectionChange(value) {
selectionData.value = value;
}
const [register, {}] = useForm({
rowProps: { gutter: [16, 0] },
colProps: {
xs: 24,
sm: 24,
md: 12,
lg: 8,
xl: 6,
},
labelCol: { span: 6, offset: 0 },
schemas,
});
//添加
const addUser = async () => {
userId.value = 0;
await nextTick();
editVisible.value = true;
};
//导出
const handleExport = async () => {
exportLoading.value = true;
const data = await userExport();
downloadByData(data, '用户信息.xlsx');
exportLoading.value = false;
message.success('导出成功');
};
const handlePrint = async (id) => {
const res = await getUserDocument(id);
printJS({
printable: res.fileUrl,
type: 'pdf',
showModal: true,
});
};
</script>

View File

@ -1,19 +0,0 @@
import { h } from 'vue';
export const cacheNameColumns = [
{
title: '缓存名称',
dataIndex: 'cacheName',
},
{
title: '备注',
dataIndex: 'message',
},
{
title: '操作',
fixed:'right',
dataIndex: 'action',
key: 'action',
width: 100,
},
];

View File

@ -1,241 +0,0 @@
<template>
<PageWrapper>
<a-row :gutter="10" class="mt-3">
<a-col :xs="24" :sm="24" :md="6" :lg="6" :xl="6">
<a-card shadow="hover" class="border-0">
<template #title>
<a-row>
<a-col :span="10">
<a-input
type="text"
v-model:value="params.name"
placeholder="请输入字典名称"
allow-clear
/>
</a-col>
<a-col :span="14" style="text-align: right">
<a-button
type="primary"
@click="
pager.page = 1;
loadDataTable();
"
>
<template #icon> <SearchOutlined /> </template>查询
</a-button>
<a-button
type="primary"
@click="dictRefresh"
style="margin-left: 8px"
v-perm="['sys:dict:cache']"
>
<template #icon> <RedoOutlined /> </template>刷新缓存</a-button
>
</a-col>
</a-row>
<div style="margin-top: 15px">
<a-space>
<a-button type="primary" @click="handleAdd" v-perm="['sys:dict:add']">
<template #icon>
<PlusOutlined />
</template>
新建
</a-button>
<a-button type="warning" @click="handleEdit" v-perm="['sys:dict:edit']">
<template #icon> <EditOutlined /> </template>编辑
</a-button>
<a-button type="danger" @click="handleDelete()" v-perm="['sys:dict:delete']">
<template #icon> <DeleteOutlined /> </template>删除
</a-button>
</a-space>
</div>
</template>
<div :style="{ height: fwbHeight + 'px' }" class="dict-list-box">
<div
v-for="(item, index) in dictDataList"
:key="index"
@click="onCheckedRow(item)"
class="dict-item"
:class="item.id == dictId ? 'active' : ''"
>
<span class="t1"
>{{ item.name }}<span class="t2">({{ item.code }})</span></span
>
</div>
</div>
<pagination
style="justify-content: flex-end"
class="mt-10 flex"
@change="loadDataTable"
v-model="pager"
/>
</a-card>
</a-col>
<a-col :xs="24" :sm="24" :md="18" :lg="18" :xl="18">
<a-card shadow="hover" class="mb-4 border-0 proCard">
<dictItem :dictId="dictId" v-if="dictItemShow" />
</a-card>
</a-col>
</a-row>
<editDialog
v-if="editVisible"
:dictId="dictId"
v-model:visible="editVisible"
@success="loadDataTable()"
/>
</PageWrapper>
</template>
<script lang="ts" setup>
import { ref, nextTick, defineAsyncComponent, onMounted } from 'vue';
import { SearchOutlined } from '@ant-design/icons-vue';
import { getDictList, refreshCache, dictDelete } from '@/api/data/dictionary';
import { PlusOutlined, EditOutlined, DeleteOutlined, RedoOutlined } from '@ant-design/icons-vue';
import dictItem from './dictItem.vue';
import { Modal, message } from 'ant-design-vue';
/**
* 导入组件
*/
const editDialog = defineAsyncComponent(() => import('./edit.vue'));
/**
* 定义参数变量
*/
const dictId = ref(0);
const dictItemShow = ref(false);
const editVisible = ref(false);
/**
* 定义查询参数
*/
const params = ref({
name: '',
});
const dictDataList = ref([]);
/**
* 定义分页参数
*/
const pager = ref({
page: 1,
size: 20,
count: dictDataList.value.length,
});
const fwbHeight = document.body.clientHeight - 370;
/**
* 添加字典
*/
const handleAdd = async () => {
await nextTick();
editVisible.value = true;
};
/**
* 刷新缓存
*/
async function dictRefresh() {
await refreshCache();
message.success('刷新成功');
}
/**
* 执行编辑
*/
const handleEdit = () => {
editVisible.value = true;
};
/**
* 数据行选中事件
* @param row 参数
*/
function onCheckedRow(row) {
dictId.value = row.id;
}
/**
* 加载数据列表
*/
const loadDataTable = async () => {
const result = await getDictList({
...params.value,
pageNo: pager.value.page,
pageSize: pager.value.size,
});
dictId.value = result?.records[0]?.id;
dictItemShow.value = true;
dictDataList.value = result.records;
pager.value.count = result.total;
};
/**
* 执行删除
*/
async function handleDelete() {
Modal.confirm({
title: '提示',
content: '确定要删除?',
onOk: async () => {
dictDelete(dictId.value);
message.success('删除成功');
pager.value.page = 1;
loadDataTable();
},
});
}
/**
* 钩子函数
*/
onMounted(() => {
loadDataTable();
});
</script>
<style lang="less" scoped>
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.dict-list-box {
overflow: auto;
.dict-item {
height: 40px;
line-height: 40px;
padding: 0 6px;
cursor: pointer;
display: flex;
justify-content: space-between;
.t1 {
font-size: 14px;
display: block;
font-weight: 700;
.t2 {
font-size: 12px;
font-weight: normal;
}
}
&.active {
background-color: #e8f1ff;
border-radius: 3px;
.t1 {
color: #1677ff;
}
.t2 {
color: rgb(22, 119, 255, 0.8);
}
}
.ant-badge__content.is-fixed {
top: 20px;
right: calc(-10px + var(--ant-badge-size) / 2);
}
}
}
</style>

View File

@ -1,19 +0,0 @@
const allModules = import.meta.globEager('./*/index.ts');
const modules = {} as any;
Object.keys(allModules).forEach((path) => {
const fileName = path.split('/')[1];
modules[fileName] = allModules[path][fileName] || allModules[path].default || allModules[path];
});
// export default modules
import asyncRoute from './async-route';
import user from './user';
import tabsView from './tabs-view';
import lockscreen from './lockscreen';
export default {
asyncRoute,
user,
tabsView,
lockscreen,
};

View File

@ -1,60 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 列表
*/
export function getAdList(params?) {
return http.request({
url: '/ad/page',
method: 'GET',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getAdDetail(adId) {
return http.request({
url: '/ad/detail/' + adId,
method: 'get',
});
}
/**
* @description: 添加
*/
export function adAdd(data: any) {
return http.request({
url: '/ad/add',
method: 'POST',
data,
});
}
/**
* @description: 更新
*/
export function adUpdate(data: any) {
return http.request({
url: '/ad/update',
method: 'PUT',
data,
});
}
/**
* @description: 删除
*/
export function adDelete(adId) {
return http.request({
url: '/ad/delete/' + adId,
method: 'DELETE',
});
}
/**
* @description: 批量删除
*/
export function adBatchDelete(data: any) {
return http.request({
url: '/ad/batchDelete',
method: 'DELETE',
data,
});
}

View File

@ -1,50 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 消息列表
*/
export function getMessageProfile(params?) {
return http.request({
url: '/message/profile',
method: 'GET',
params,
});
}
/**
* @description: 设置消息已读
*/
export function setRead(data?) {
return http.request({
url: '/message/setRead',
method: 'POST',
data,
});
}
/**
* @description: 根据ID获取详情
*/
export function getMessageDetail(id) {
return http.request({
url: '/message/detail/' + id,
method: 'get',
});
}
/**
* @description: 删除消息
*/
export function messageDelete(id) {
return http.request({
url: '/message/delete/' + id,
method: 'DELETE',
});
}
/**
* @description: 批量删除消息
*/
export function messageBatchDelete(data: any) {
return http.request({
url: '/message/batchDelete',
method: 'DELETE',
data,
});
}

View File

@ -1,8 +0,0 @@
import { generatorMenu } from '@/utils/index';
import { useAsyncRouteStore } from '@/store/modules/asyncRoute';
import { Menu } from '../types';
export const getMenus = async (): Promise<Menu[]> => {
const asyncRouteStore = useAsyncRouteStore();
return generatorMenu(asyncRouteStore.getMenus);
};

View File

@ -1,86 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 角色列表
*/
export function getRoleList(params?) {
return http.request({
url: '/role/page',
method: 'GET',
params,
});
}
export function getRoleAllList(params?) {
return http.request({
url: '/role/list',
method: 'GET',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getRoleDetail(roleId) {
return http.request({
url: '/role/detail/'+roleId,
method: 'get',
});
}
/**
* @description: 添加角色
*/
export function roleAdd(data:any) {
return http.request({
url: '/role/add',
method: 'POST',
data,
});
}
/**
* @description: 更新角色
*/
export function roleUpdate(data:any) {
return http.request({
url: '/role/update',
method: 'PUT',
data
});
}
/**
* @description: 删除角色
*/
export function roleDelete(roleId) {
return http.request({
url: '/role/delete/'+roleId,
method: 'DELETE',
});
}
/**
* @description: 批量删除角色
*/
export function roleBatchDelete(data) {
return http.request({
url: '/role/batchDelete',
method: 'DELETE',
data
});
}
/**
* @description: 获取角色菜单
*/
export function getRoleMenuList(roleId) {
return http.request({
url: '/role/menu/list/'+roleId,
method: 'get',
});
}
/**
* @description: 保存角色菜单
*/
export function roleMenuSave(data:any) {
return http.request({
url: '/role/menu/save',
method: 'POST',
data,
});
}

View File

@ -1,36 +0,0 @@
import type { PropType } from 'vue';
export const basicProps = {
value: {
type: [Array, Object, String, Number],
default: undefined,
},
request: {
type: Function as PropType<(...arg: any[]) => Promise<any>>,
default: null,
required: true,
},
//是否缓存数据
cache: {
type: Boolean,
default: false,
},
//开启缓存必传缓存key否则不生效
cacheKey: {
type: String,
default: '',
},
width: {
type: Number as PropType<number>,
default: 150,
},
//block属性将使按钮适合其父宽度
block: {
type: Boolean,
default: false,
},
placeholder: {
type: String,
default: '请选择',
},
};

View File

@ -1,140 +0,0 @@
<template>
<PageWrapper>
<a-card :bordered="false" class="pt-3 mb-3 proCard">
<BasicForm @register="register" @submit="handleSubmit" @reset="handleReset" />
</a-card>
<a-card :bordered="false" class="proCard">
<BasicTable
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
ref="tableRef"
:row-selection="{ onChange: onSelectionChange }"
>
<template #tableTitle>
<a-button
type="danger"
@click="handleDelete()"
:disabled="!selectionData.length"
v-perm="['sys:emailLog:batchDelete']"
>
<template #icon>
<DeleteOutlined />
</template>
删除
</a-button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<a-space>
<a-button
type="primary"
@click="handleInfo(record.id)"
v-perm="['sys:emailLog:detail']"
>
<template #icon><EditOutlined /></template>
详情
</a-button>
<a-button
type="primary"
danger
@click="handleDelete(record.id)"
v-perm="['sys:emailLog:delete']"
>
<template #icon><DeleteOutlined /></template>
删除
</a-button>
</a-space>
</template>
</template>
</BasicTable>
</a-card>
<editDialog
v-if="editVisible"
:emailId="emailId"
v-model:visible="editVisible"
@success="reloadTable('noRefresh')"
/>
</PageWrapper>
</template>
<script lang="ts" setup>
import { reactive, ref, h, nextTick, defineAsyncComponent } from 'vue';
import { EditOutlined, DeleteOutlined } from '@ant-design/icons-vue';
import { schemas } from './querySchemas';
import { useForm } from '@/components/Form/index';
import { getEmailLogList, emailLogDelete, emailLogBatchDelete } from '@/api/logger/emailLog';
import { columns } from './columns';
import { Modal, message } from 'ant-design-vue';
const editDialog = defineAsyncComponent(() => import('./edit.vue'));
const emailId = ref(0);
const editVisible = ref(false);
const selectionData = ref([]);
const tableRef = ref();
const formParams = reactive({
title: '',
receiveType: '',
bizType: '',
status: '',
});
const loadDataTable = async (res: any) => {
const result = await getEmailLogList({ ...formParams, ...res });
return result;
};
function reloadTable(noRefresh = '') {
tableRef.value.reload(noRefresh ? {} : { pageNo: 1 });
}
const [register, {}] = useForm({
rowProps: { gutter: [16, 0] },
colProps: {
xs: 24,
sm: 24,
md: 12,
lg: 8,
xl: 6,
},
labelCol: { span: 6, offset: 0 },
schemas,
});
function handleSubmit(values) {
for (const key in formParams) {
formParams[key] = '';
}
for (const key in values) {
formParams[key] = values[key];
}
reloadTable();
}
function handleReset() {
for (const key in formParams) {
formParams[key] = '';
}
reloadTable();
}
const handleInfo = async (id) => {
emailId.value = id;
await nextTick();
editVisible.value = true;
};
async function handleDelete(id) {
Modal.confirm({
title: '提示',
content: '确定要删除?',
onOk: async () => {
id ? await emailLogDelete(id) : await emailLogBatchDelete(selectionData.value);
message.success('删除成功');
reloadTable();
},
});
}
function onSelectionChange(value) {
selectionData.value = value;
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,9 +0,0 @@
/dist/*
.local
.output.js
/node_modules/**
**/*.svg
**/*.sh
/public/*

View File

@ -1,99 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 角色列表
*/
export function getRoleList(params?) {
return http.request({
url: '/role/page',
method: 'GET',
params,
});
}
/**
* 获取全部角色列表
* @param params 参数
* @returns 返回结果
*/
export function getRoleAllList(params?) {
return http.request({
url: '/role/list',
method: 'GET',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getRoleDetail(roleId) {
return http.request({
url: '/role/detail/' + roleId,
method: 'get',
});
}
/**
* @description: 添加角色
*/
export function roleAdd(data: any) {
return http.request({
url: '/role/add',
method: 'POST',
data,
});
}
/**
* @description: 更新角色
*/
export function roleUpdate(data: any) {
return http.request({
url: '/role/update',
method: 'PUT',
data,
});
}
/**
* @description: 删除角色
*/
export function roleDelete(roleId) {
return http.request({
url: '/role/delete/' + roleId,
method: 'DELETE',
});
}
/**
* @description: 批量删除角色
*/
export function roleBatchDelete(data) {
return http.request({
url: '/role/batchDelete',
method: 'DELETE',
data,
});
}
/**
* @description: 获取角色菜单
*/
export function getRoleMenuList(roleId) {
return http.request({
url: '/role/menu/list/' + roleId,
method: 'get',
});
}
/**
* @description: 保存角色菜单
*/
export function roleMenuSave(data: any) {
return http.request({
url: '/role/menu/save',
method: 'POST',
data,
});
}

View File

@ -1,115 +0,0 @@
import { h } from 'vue';
import { Tag,Avatar } from 'ant-design-vue';
export const columns = [
{
title: 'ID',
dataIndex: 'id',
fixed:'left',
width: 100,
},
{
title: '广告标题',
dataIndex: 'title',
width: 250,
customRender({ record }) {
return h('a', {
href: record.url,
target:"_blank"
}, record.title);
},
},
{
title: '广告封面',
dataIndex: 'cover',
customRender({ record }) {
return h(Avatar, {
size: 35,
src: record.cover,
shape: 'square',
fit: 'fill',
});
},
width: 100,
},
{
title: '广告类型',
dataIndex: 'type',
customRender({ record }) {
let typeText = ''
switch (record.type) {
case 1:
typeText='图片'
break;
case 2:
typeText='文字'
break;
case 3:
typeText='视频'
break;
default:
break;
}
return h('span', typeText || '-');
},
width:100
},
{
title: '广告状态',
dataIndex: 'status',
customRender({ record }) {
return h(
Tag,
{
color: record.status ==1 ? 'success' : 'error',
},
{
default: () => (record.status ==1 ? '正常' : '停用'),
},
);
},
width:100
},
{
title: '广告尺寸',
dataIndex: 'size',
customRender({ record }) {
return record.width + 'x' + record.height;
},
width:100
},
{
title: '投放时间',
dataIndex: 'time',
customRender({ record }) {
return record.startTime + '-' + record.endTime;
},
width:300
},
{
title: '点击量',
dataIndex: 'click',
width:100
},
{
title: '排序',
dataIndex: 'sort',
width:100
},
{
title: '创建人',
dataIndex: 'createUser',
width:100
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 180,
},
{
title: '操作',
fixed:'right',
dataIndex: 'action',
key: 'action',
width: 200,
},
];

View File

@ -1,76 +0,0 @@
import { h } from 'vue';
import { Tag,Avatar } from 'ant-design-vue';
export const columns = [
{
title:'ID',
dataIndex: 'id',
width:100
},
{
title: '文章标题',
dataIndex: 'title',
customRender({ record }) {
return h('a', {
href: 'http://www.baidu.com',
target:"_blank"
},record.title);
},
},
{
title: '文章分类',
dataIndex: 'categoryName',
},
{
title: '文章封面',
dataIndex: 'cover',
key: 'cover',
customRender({ record }) {
return h(Avatar, {
size: 48,
src: record.cover,
shape: 'square',
fit: 'fill',
});
},
width: 100,
},
{
title: '文章分类',
dataIndex: 'categoryName',
},
{
title: '文章作者',
dataIndex: 'author',
},
{
title: '文章状态',
dataIndex: 'status',
customRender({ record }) {
return h(
Tag,
{
color: record.status ==1 ? 'error' : 'success',
},
{
default: () => (record.status ==1 ? '下架' : '正常'),
},
);
},
},
{
title: '创建人',
dataIndex: 'createUser',
},
{
title: '创建时间',
dataIndex: 'createTime',
},
{
title: '操作',
fixed:'right',
dataIndex: 'action',
key: 'action',
width: 200,
},
];

View File

@ -1,186 +0,0 @@
<template>
<PageWrapper>
<a-card :bordered="false" class="pt-3 mb-3 proCard">
<BasicForm @register="register" @submit="handleSubmit" @reset="handleReset" />
</a-card>
<a-card :bordered="false" class="proCard">
<BasicTable
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
ref="tableRef"
:row-selection="{ onChange: onSelectionChange }"
>
<template #tableTitle>
<a-button
type="danger"
@click="handleDelete()"
:disabled="!selectionData.length"
v-perm="['sys:loginLog:batchDelete']"
>
<template #icon>
<DeleteOutlined />
</template>
删除
</a-button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<a-space>
<a-button
type="primary"
@click="handleDetail(record.id)"
v-perm="['sys:loginLog:detail']"
>
<template #icon><EyeOutlined /></template>
详情
</a-button>
<a-button
type="primary"
danger
@click="handleDelete(record.id)"
v-perm="['sys:loginLog:delete']"
>
<template #icon><DeleteOutlined /></template>
删除
</a-button>
</a-space>
</template>
</template>
</BasicTable>
</a-card>
<editDialog
v-if="editVisible"
:loginlogId="loginlogId"
v-model:visible="editVisible"
@success="reloadTable('noRefresh')"
/>
</PageWrapper>
</template>
<script lang="ts" setup>
import { reactive, ref, h, nextTick, defineAsyncComponent } from 'vue';
import { EyeOutlined, DeleteOutlined } from '@ant-design/icons-vue';
import { schemas } from './loginLog/querySchemas';
import { useForm } from '@/components/Form/index';
import { TableAction } from '@/components/Table';
import { getLoginLogList, loginLogDelete, loginLogBatchDelete } from '@/api/system/loginLog';
import { columns } from './loginLog/columns';
import { Modal, message } from 'ant-design-vue';
/**
* 导入组件
*/
const editDialog = defineAsyncComponent(() => import('./loginLog/edit.vue'));
/**
* 定义参数变量
*/
const loginlogId = ref(0);
const editVisible = ref(false);
const selectionData = ref([]);
const tableRef = ref();
/**
* 定义查询参数
*/
const formParams = reactive({
username: '',
type: '',
status: '',
});
/**
* 加载数据列表
* @param res 参数
*/
const loadDataTable = async (res: any) => {
const result = await getLoginLogList({ ...formParams, ...res });
return result;
};
/**
* 刷新数据列表
* @param noRefresh 参数
*/
function reloadTable(noRefresh = '') {
tableRef.value.reload(noRefresh ? {} : { pageNo: 1 });
}
/**
* 注册
*/
const [register, {}] = useForm({
rowProps: { gutter: [16, 0] },
colProps: {
xs: 24,
sm: 24,
md: 12,
lg: 8,
xl: 6,
},
labelCol: { span: 6, offset: 0 },
schemas,
});
/**
* 执行提交表单
* @param values 参数
*/
function handleSubmit(values) {
for (const key in formParams) {
formParams[key] = '';
}
for (const key in values) {
formParams[key] = values[key];
}
reloadTable();
}
/**
* 执行重置
*/
function handleReset() {
for (const key in formParams) {
formParams[key] = '';
}
reloadTable();
}
/**
* 执行查询详情
* @param id 参数
*/
const handleDetail = async (id) => {
loginlogId.value = id;
await nextTick();
editVisible.value = true;
};
/**
* 执行删除
* @param id 参数
*/
async function handleDelete(id) {
Modal.confirm({
title: '提示',
content: '确定要删除?',
onOk: async () => {
id ? await loginLogDelete(id) : await loginLogBatchDelete(selectionData.value);
message.success('删除成功');
reloadTable();
},
});
}
/**
* 选项发生变化
* @param value 参数
*/
function onSelectionChange(value) {
selectionData.value = value;
}
</script>
<style lang="scss" scoped></style>

View File

@ -1,64 +0,0 @@
import { h } from 'vue';
import { Tag,Avatar } from 'ant-design-vue';
export const columns = [
{
title: 'ID',
dataIndex: 'id',
width: 100,
},
{
title: '位置描述',
dataIndex: 'description',
width: 250,
customRender({ record }) {
return record.description + ">>" + record.location;
},
},
{
title: '推荐类型',
dataIndex: 'typeText',
},
{
title: '推荐ID',
dataIndex: 'typeId',
},
{
title: '推荐图片',
dataIndex: 'image',
customRender({ record }) {
return h(Avatar, {
size: 48,
src: record.image,
shape: 'square',
fit: 'fill',
});
},
width: 120,
},
{
title: '推荐标题',
dataIndex: 'typeTitle',
width: 200,
},
{
title: '排序',
dataIndex: 'sort',
},
{
title: '创建人',
dataIndex: 'createUser',
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 180,
},
{
title: '操作',
fixed:'right',
dataIndex: 'action',
key: 'action',
width: 200,
},
];

View File

@ -1,52 +0,0 @@
import { h } from 'vue';
import { ElTag } from 'element-plus';
export const columns = [
{
title: '数据表名称',
dataIndex: 'tableName',
width: 150,
},
{
title: '数据表描述',
dataIndex: 'tableComment',
width: 150,
},
{
title: '数据表引擎',
dataIndex: 'engine',
width: 100,
},
{
title: '数据表行数',
dataIndex: 'tableRows',
width: 100,
},
{
title: '数据表长度',
dataIndex: 'dataLength',
width: 100,
},
{
title: '数据表自增索引',
dataIndex: 'autoIncrement',
width: 100,
},
{
title: '数据表编码',
dataIndex: 'tableCollation',
width: 150,
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 180,
},
{
title: '操作',
fixed: 'right',
dataIndex: 'action',
key: 'action',
width: 130,
},
];

View File

@ -1,85 +0,0 @@
<template>
<a-modal v-model:visible="props.visible" title="日志详情" width="800px" @cancel="dialogClose">
<a-descriptions :column="2" bordered :labelStyle="{ width: '160px' }">
<a-descriptions-item label="任务名称:">{{ formData.jobName }}</a-descriptions-item>
<a-descriptions-item label="任务组名:">{{ formData.jobGroup }}</a-descriptions-item>
<a-descriptions-item label="任务触发器:">{{ formData.jobTrigger }}</a-descriptions-item>
<a-descriptions-item label="任务信息:">{{ formData.jobMessage }}</a-descriptions-item>
<a-descriptions-item label="cron执行表达式:">{{
formData.cronExpression
}}</a-descriptions-item>
<a-descriptions-item label="任务开始时间:">{{ formData.startTime }}</a-descriptions-item>
<a-descriptions-item label="任务结束时间:">{{ formData.endTime }}</a-descriptions-item>
</a-descriptions>
<template #footer>
<span class="dialog-footer">
<a-button @click="dialogClose">关闭</a-button>
</span>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import { getJobLogDetail } from '@/api/monitor/job';
import { onMounted, reactive, shallowRef } from 'vue';
/**
* 定义表单参数
*/
const formData = reactive({
id: '',
jobName: '',
jobGroup: '',
jobTrigger: '',
jobMessage: '',
cronExpression: '',
startTime: '',
endTime: '',
});
const emit = defineEmits(['update:visible']);
/**
* 定义接收的参数
*/
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
logId: {
type: Number,
required: true,
default: 0,
},
});
/**
* 关闭窗体
*/
const dialogClose = () => {
emit('update:visible', false);
};
/**
* 设置表单数据
*/
const setFormData = async () => {
const data = await getJobLogDetail(props.logId);
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key];
}
}
};
/**
* 钩子函数
*/
onMounted(() => {
if (props.logId) {
setFormData();
}
});
</script>

View File

@ -1,34 +0,0 @@
import { FormSchema } from '@/components/Form/index';
export const schemas: FormSchema[] = [
{
name: 'title',
component: 'Input',
label: '模板名称',
componentProps: {
placeholder: '请输入模板名称',
},
},
{
name: 'type',
component: 'Select',
label: '模板类型',
componentProps: {
placeholder: '请选择模板类型',
clearable: true,
options: [
{
label: '阿里云',
value: '1',
},
{
label: '腾讯云',
value: '2',
},
{
label: '华为云',
value: '3',
},
],
},
},
];

View File

@ -1,115 +0,0 @@
import { h } from 'vue';
import { Tag } from 'ant-design-vue';
export const columns = [
{
title: 'ID',
dataIndex: 'id',
fixed: 'left',
width: 50,
},
{
title: '配置项名称',
dataIndex: 'name',
width: 100,
},
{
title: '配置项编码',
dataIndex: 'code',
width: 100,
},
{
title: '配置项值',
dataIndex: 'value',
width: 100,
},
{
title: '配置项类型',
dataIndex: 'type',
width: 100,
customRender({ record }) {
let typeText = '';
switch (record.type) {
case 'hidden':
typeText = '隐藏';
break;
case 'readonly':
typeText = '只读文本';
break;
case 'number':
typeText = '数字';
break;
case 'text':
typeText = '单行文本';
break;
case 'textarea':
typeText = '多行文本';
break;
case 'password':
typeText = '密码';
break;
case 'radio':
typeText = '单选框';
break;
case 'checkbox':
typeText = '复选框';
break;
case 'select':
typeText = '下拉框(单选)';
break;
case 'selects':
typeText = '下拉框(多选)';
break;
case 'icon':
typeText = '字体图标';
break;
case 'date':
typeText = '日期';
break;
case 'datetime':
typeText = '时间';
break;
case 'image':
typeText = '单张图片';
break;
case 'images':
typeText = '多张图片';
break;
case 'file':
typeText = '单个文件';
break;
case 'files':
typeText = '多个文件';
break;
case 'ueditor':
typeText = '富文本编辑器';
break;
default:
break;
}
return h('span', typeText || '-');
},
},
{
title: '配置项状态',
dataIndex: 'status',
width: 100,
customRender({ record }) {
return h(
Tag,
{
color: record.status == 1 ? 'success' : 'error',
},
{
default: () => (record.status == 1 ? '正常' : '停用'),
},
);
},
},
{
title: '操作',
fixed: 'right',
dataIndex: 'action',
key: 'action',
width: 200,
},
];

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

View File

@ -1,36 +0,0 @@
import { h } from 'vue';
export const columns = [
{
title: 'ID',
dataIndex: 'id',
fixed: 'left',
width: 50,
},
{
title: '消息标题',
dataIndex: 'title',
},
{
title: '消息状态',
dataIndex: 'status',
customRender({ record }) {
return h('span', record.status === 1 ? '已读' : '未读')
},
},
{
title: '创建人',
dataIndex: 'createUser',
},
{
title: '创建时间',
dataIndex: 'createTime',
},
{
title: '操作',
fixed: 'right',
dataIndex: 'action',
key: 'action',
width: 300,
},
];

View File

@ -1,65 +0,0 @@
import { h } from 'vue';
import { Tag } from 'ant-design-vue';
export const columns = [
{
title: 'ID',
dataIndex: 'id',
width: 100,
},
{
title: '任务名称',
dataIndex: 'jobName',
},
{
title: '任务分组',
dataIndex: 'jobGroup',
},
{
title: '任务触发器',
dataIndex: 'jobTrigger',
},
{
title: '执行表达式',
dataIndex: 'cronExpression',
},
{
title: '执行策略',
dataIndex: 'executePolicyText',
},
{
title: '同步任务',
dataIndex: 'isSync',
customRender({ record }) {
return h(
Tag,
{
color: record.isSync == 1 ? 'processing' : 'warning',
},
{
default: () => (record.isSync == 1 ? '同步' : '异步'),
},
);
},
},
{
title: 'URL',
dataIndex: 'url',
},
{
title: '状态',
key:'status',
dataIndex:'status'
},
{
title: '备注',
dataIndex: 'note',
},
{
title: '操作',
fixed:'right',
dataIndex: 'action',
key: 'action',
width: 330,
},
];

View File

@ -1,112 +0,0 @@
<template>
<a-modal
v-model:visible="props.visible"
:title="props.configId ? '编辑' : '新增'"
width="500px"
@cancel="dialogClose"
>
<a-form
class="ls-form"
ref="formRef"
:model="formData"
:label-col="{ style: { width: '80px' } }"
>
<a-form-item
label="配置名称"
name="name"
:rules="{ required: true, message: '请输入配置名称', trigger: 'blur' }"
>
<a-input v-model:value="formData.name" placeholder="请输入名称" allow-clear />
</a-form-item>
<a-form-item
label="配置编码"
name="code"
:rules="{ required: true, message: '请输入配置编码', trigger: 'blur' }"
>
<a-input
v-model:value="formData.code"
:disabled="props.configId"
placeholder="请输入配置编码"
allow-clear
/>
</a-form-item>
<a-form-item label="排序" name="sort">
<a-input-number v-model:value="formData.sort" />
</a-form-item>
<a-form-item label="备注" name="note">
<a-input
v-model:value="formData.note"
type="textarea"
placeholder="请输入备注"
allow-clear
/>
</a-form-item>
</a-form>
<template #footer>
<span class="dialog-footer">
<a-button @click="dialogClose">取消</a-button>
<a-button :loading="subLoading" type="primary" @click="submit"> 确定 </a-button>
</span>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'ant-design-vue';
import { getConfigDetail, configAdd, configUpdate } from '@/api/data/config';
import { onMounted, reactive, shallowRef } from 'vue';
import { message } from 'ant-design-vue';
import { useLockFn } from '@/utils/useLockFn';
const emit = defineEmits(['success', 'update:visible']);
const formRef = shallowRef<FormInstance>();
const formData = reactive({
id: '',
name: '',
code: '',
sort: 0,
note: '',
});
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
configId: {
type: Number,
required: true,
default: 0,
},
});
const handleSubmit = async () => {
await formRef.value?.validate();
props.configId ? await configUpdate(formData) : await configAdd(formData);
message.success('操作成功');
emit('update:visible', false);
emit('success');
};
const dialogClose = () => {
emit('update:visible', false);
};
const { isLock: subLoading, lockFn: submit } = useLockFn(handleSubmit);
const setFormData = async () => {
const data = await getConfigDetail(props.configId);
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key];
}
}
};
onMounted(() => {
if (props.configId) {
setFormData();
}
});
</script>

View File

@ -1,148 +0,0 @@
<template>
<PageWrapper>
<a-card :bordered="false" class="pt-3 mb-3 proCard">
<BasicForm @register="register" @submit="handleSubmit" @reset="handleReset">
<template #statusSlot="{ model, field }">
<a-input v-model="model[field]" />
</template>
</BasicForm>
</a-card>
<a-card :bordered="false" class="proCard">
<BasicTable
:columns="columns"
:request="loadDataTable"
:row-key="(row) => row.id"
ref="tableRef"
scroll-x="1200"
:row-selection="{onChange: onSelectionChange}"
virtual-scroll
>
<template #tableTitle>
<a-space>
<a-button type="primary" @click="handleAdd" v-perm="['sys:messageTemplate:add']">
<template #icon>
<PlusOutlined />
</template>
新建
</a-button>
<a-button type="danger" @click="handleDelete()" :disabled="!selectionData.length" v-perm="['sys:messageTemplate:batchDelete']">
<template #icon>
<DeleteOutlined />
</template>
删除
</a-button>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<a-space>
<a-button type="primary" @click="handleEdit(record.id)" v-perm="['sys:messageTemplate:update']">
<template #icon><EditOutlined /></template>
编辑
</a-button>
<a-button type="primary" danger @click="handleDelete(record.id)" v-perm="['sys:messageTemplate:delete']">
<template #icon><DeleteOutlined /></template>
删除
</a-button>
</a-space>
</template>
</template>
</BasicTable>
</a-card>
<editDialog
v-if="editVisible"
:id="fileId"
v-model:visible="editVisible"
@success="reloadTable('noRefresh')"
>
</editDialog>
</PageWrapper>
</template>
<script lang="ts" setup>
import { h, nextTick, reactive, ref ,defineAsyncComponent} from 'vue';
import { PlusOutlined,EditOutlined,DeleteOutlined} from '@ant-design/icons-vue';
import { useForm } from '@/components/Form/index';
import { getMessageTemplateList,messageTemplateDelete,messageTemplateBatchDelete } from '@/api/file/messageTemplate';
import { columns } from './columns';
import { schemas } from './querySchemas';
import { Modal,message } from 'ant-design-vue';
const fileId = ref(0);
const tableRef = ref();
const editVisible = ref(false)
const selectionData = ref([])
const editDialog = defineAsyncComponent(() =>
import('./edit.vue'))
const formParams = reactive({
title: '',
type:''
});
const loadDataTable = async (res) => {
const result = await getMessageTemplateList({ ...formParams, ...res });
return result;
};
function reloadTable(noRefresh='') {
tableRef.value.reload(noRefresh?{}:{pageNo:1});
}
async function handleEdit(id) {
fileId.value=id
await nextTick();
editVisible.value=true
}
async function handleDelete(id) {
Modal.confirm({
title: '提示',
content: "确定要删除?",
onOk: async () => {
id? await messageTemplateDelete(id):await messageTemplateBatchDelete(selectionData.value);
message.success("删除成功");
reloadTable()
}
});
}
function handleSubmit(values) {
for (const key in formParams) {
formParams[key] ='';
}
for (const key in values) {
formParams[key] = values[key]
}
reloadTable();
}
function handleReset() {
for (const key in formParams) {
formParams[key] ='';
}
reloadTable();
}
function onSelectionChange(value){
selectionData.value = value
}
const [register, {}] = useForm({
rowProps: { gutter: [16, 0] },
colProps: {
xs: 24,
sm: 24,
md: 12,
lg: 8,
xl: 6,
},
labelCol: { span: 6, offset: 0 },
schemas
});
//添加
const handleAdd = async () => {
fileId.value=0
await nextTick();
editVisible.value=true
};
</script>

View File

@ -1,12 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 缓存监控信息
*/
export function getCacheInfo(params?) {
return http.request({
url: '/admin/cache/info',
method: 'GET',
params,
});
}

View File

@ -1,91 +0,0 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
/**
* Jquery integration plugin.
*
* @class tinymce.core.JqueryIntegration
* @private
*/
!function(){function f(){
// Reference to tinymce needs to be lazily evaluated since tinymce
// might be loaded through the compressor or other means
return d.tinymce}var p,c,u,s=[],d="undefined"!=typeof global?global:window,m=d.jQuery;m.fn.tinymce=function(o){var e,t,i,n,l=this,r="";
// No match then just ignore the call
return l.length?
// Get editor instance
o?(l.css("visibility","hidden"),
// Load TinyMCE on demand, if we need to
d.tinymce||c||!(e=o.script_url)?
// Delay the init call until tinymce is loaded
1===c?s.push(a):a():(c=1,t=e.substring(0,e.lastIndexOf("/")),
// Check if it's a dev/src version they want to load then
// make sure that all plugins, themes etc are loaded in source mode as well
-1!=e.indexOf(".min")&&(r=".min"),
// Setup tinyMCEPreInit object this will later be used by the TinyMCE
// core script to locate other resources like CSS files, dialogs etc
// You can also predefined a tinyMCEPreInit object and then it will use that instead
d.tinymce=d.tinyMCEPreInit||{base:t,suffix:r},
// url contains gzip then we assume it's a compressor
-1!=e.indexOf("gzip")&&(i=o.language||"en",e=e+(/\?/.test(e)?"&":"?")+"js=true&core=true&suffix="+escape(r)+"&themes="+escape(o.theme||"modern")+"&plugins="+escape(o.plugins||"")+"&languages="+(i||""),
// Check if compressor script is already loaded otherwise setup a basic one
d.tinyMCE_GZ||(d.tinyMCE_GZ={start:function(){function n(e){f().ScriptLoader.markDone(f().baseURI.toAbsolute(e))}
// Add core languages
n("langs/"+i+".js"),
// Add themes with languages
n("themes/"+o.theme+"/theme"+r+".js"),n("themes/"+o.theme+"/langs/"+i+".js"),
// Add plugins with languages
m.each(o.plugins.split(","),function(e,t){t&&(n("plugins/"+t+"/plugin"+r+".js"),n("plugins/"+t+"/langs/"+i+".js"))})},end:function(){}})),(n=document.createElement("script")).type="text/javascript",n.onload=n.onreadystatechange=function(e){e=e||window.event,2===c||"load"!=e.type&&!/complete|loaded/.test(n.readyState)||(f().dom.Event.domLoaded=1,c=2,
// Execute callback after mainscript has been loaded and before the initialization occurs
o.script_loaded&&o.script_loaded(),a(),m.each(s,function(e,t){t()}))},n.src=e,document.body.appendChild(n)),l):f()?f().get(l[0].id):null:l;function a(){var a=[],c=0;
// Apply patches to the jQuery object, only once
u||(v(),u=!0),
// Create an editor instance for each matched node
l.each(function(e,t){var n,i=t.id,r=o.oninit;
// Generate unique id for target element if needed
i||(t.id=i=f().DOM.uniqueId()),
// Only init the editor once
f().get(i)||(
// Create editor instance and render it
n=f().createEditor(i,o),a.push(n),n.on("init",function(){var e,t=r;l.css("visibility",""),
// Run this if the oninit setting is defined
// this logic will fire the oninit callback ones each
// matched editor instance is initialized
r&&++c==a.length&&("string"==typeof t&&(e=-1===t.indexOf(".")?null:f().resolve(t.replace(/\.\w+$/,"")),t=f().resolve(t)),
// Call the oninit function with the object
t.apply(e||f(),a))}))}),
// Render the editor instances in a separate loop since we
// need to have the full editors array used in the onInit calls
m.each(a,function(e,t){t.render()})}},
// Add :tinymce pseudo selector this will select elements that has been converted into editor instances
// it's now possible to use things like $('*:tinymce') to get all TinyMCE bound elements.
m.extend(m.expr[":"],{tinymce:function(e){var t;return!!(e.id&&"tinymce"in d&&(t=f().get(e.id))&&t.editorManager===f())}});
// This function patches internal jQuery functions so that if
// you for example remove an div element containing an editor it's
// automatically destroyed by the TinyMCE API
var v=function(){function r(e){
// If the function is remove
"remove"===e&&this.each(function(e,t){var n=u(t);n&&n.remove()}),this.find("span.mceEditor,div.mceEditor").each(function(e,t){var n=f().get(t.id.replace(/_parent$/,""));n&&n.remove()})}function o(i){var e,t=this;
// Handle set value
/*jshint eqnull:true */if(null!=i)r.call(t),
// Saves the contents before get/set value of textarea/div
t.each(function(e,t){var n;(n=f().get(t.id))&&n.setContent(i)});else if(0<t.length&&(e=f().get(t[0].id)))return e.getContent()}function l(e){return e&&e.length&&d.tinymce&&e.is(":tinymce")}
// Removes any child editor instances by looking for editor wrapper elements
var u=function(e){var t=null;return e&&e.id&&d.tinymce?f().get(e.id):t},s={};
// Loads or saves contents from/to textarea if the value
// argument is defined it will set the TinyMCE internal contents
// Patch some setter/getter functions these will
// now be able to set/get the contents of editor instances for
// example $('#editorid').html('Content'); will update the TinyMCE iframe instance
m.each(["text","html","val"],function(e,t){var a=s[t]=m.fn[t],c="text"===t;m.fn[t]=function(e){var t=this;if(!l(t))return a.apply(t,arguments);if(e!==p)return o.call(t.filter(":tinymce"),e),a.apply(t.not(":tinymce"),arguments),t;// return original set for chaining
var i="",r=arguments;return(c?t:t.eq(0)).each(function(e,t){var n=u(t);i+=n?c?n.getContent().replace(/<(?:"[^"]*"|'[^']*'|[^'">])*>/g,""):n.getContent({save:!0}):a.apply(m(t),r)}),i}}),
// Makes it possible to use $('#id').append("content"); to append contents to the TinyMCE editor iframe
m.each(["append","prepend"],function(e,t){var n=s[t]=m.fn[t],r="prepend"===t;m.fn[t]=function(i){var e=this;return l(e)?i!==p?("string"==typeof i&&e.filter(":tinymce").each(function(e,t){var n=u(t);n&&n.setContent(r?i+n.getContent():n.getContent()+i)}),n.apply(e.not(":tinymce"),arguments),e):void 0:n.apply(e,arguments)}}),
// Makes sure that the editor instance gets properly destroyed when the parent element is removed
m.each(["remove","replaceWith","replaceAll","empty"],function(e,t){var n=s[t]=m.fn[t];m.fn[t]=function(){return r.call(this,t),n.apply(this,arguments)}}),s.attr=m.fn.attr,
// Makes sure that $('#tinymce_id').attr('value') gets the editors current HTML contents
m.fn.attr=function(e,t){var n=this,i=arguments;if(!e||"value"!==e||!l(n))return s.attr.apply(n,i);if(t!==p)return o.call(n.filter(":tinymce"),t),s.attr.apply(n.not(":tinymce"),i),n;// return original set for chaining
var r=n[0],a=u(r);return a?a.getContent({save:!0}):s.attr.apply(m(r),i)}}}();

View File

@ -1,161 +0,0 @@
import { http } from '@/utils/http/axios';
/**
* @description: 定时任务列表
*/
export function getJobList(params?) {
return http.request({
url: '/admin/job/page',
method: 'GET',
params,
});
}
/**
* 获取全部定时任务列表
* @param params 参数
* @returns 返回结果
*/
export function getJobAllList(params?) {
return http.request({
url: '/admin/job/list',
method: 'GET',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getJobDetail(id) {
return http.request({
url: '/admin/job/detail/' + id,
method: 'get',
});
}
/**
* @description: 添加定时任务
*/
export function jobAdd(data: any) {
return http.request({
url: '/admin/job/add',
method: 'POST',
data,
});
}
/**
* @description: 更新定时任务
*/
export function jobUpdate(data: any) {
return http.request({
url: '/admin/job/update',
method: 'PUT',
data,
});
}
/**
* @description: 删除定时任务
*/
export function jobDelete(id) {
return http.request({
url: '/admin/job/delete/' + id,
method: 'DELETE',
});
}
/**
* @description: 批量删除定时任务
*/
export function jobBatchDelete(data: any) {
return http.request({
url: '/admin/job/batchDelete',
method: 'DELETE',
data,
});
}
/**
* @description: 执行一次
*/
export function getJobRunOnce(id) {
return http.request({
url: '/admin/job/runOnce/' + id,
method: 'get',
});
}
/**
* @description: 设置状态
*/
export function setJobStatus(data: any) {
return http.request({
url: '/admin/job/status',
method: 'post',
data,
});
}
/**
* @description: 暂停任务
*/
export function getJobPause(id) {
return http.request({
url: '/admin/job/pause/' + id,
method: 'get',
});
}
/**
* @description: 恢复任务
*/
export function getJobResume(id) {
return http.request({
url: '/admin/job/resume/' + id,
method: 'get',
});
}
/**
* @description: 定时任务日志列表
*/
export function getJobLogList(params?) {
return http.request({
url: '/admin/job/log/page',
method: 'GET',
params,
});
}
/**
* @description: 根据ID获取详情
*/
export function getJobLogDetail(id) {
return http.request({
url: '/admin/job/log/detail/' + id,
method: 'get',
});
}
/**
* @description: 删除定时任务日志
*/
export function jobLogDelete(id) {
return http.request({
url: '/admin/job/log/delete/' + id,
method: 'DELETE',
});
}
/**
* @description: 批量删除定时任务日志
*/
export function jobLogBatchDelete(data: any) {
return http.request({
url: '/admin/job/log/batchDelete',
method: 'DELETE',
data,
});
}

View File

@ -1,110 +0,0 @@
<template>
<a-modal v-model:visible="props.visible" title="日志详情" width="800px" @cancel="dialogClose">
<a-descriptions :column="2" bordered :labelStyle="{ width: '160px' }">
<a-descriptions-item label="任务名称:">{{ formData.jobName }}</a-descriptions-item>
<a-descriptions-item label="任务组名:">{{ formData.jobGroup }}</a-descriptions-item>
<a-descriptions-item label="任务触发器:">{{ formData.jobTrigger }}</a-descriptions-item>
<a-descriptions-item label="任务信息:">{{ formData.jobMessage }}</a-descriptions-item>
<a-descriptions-item label="cron执行表达式:">{{
formData.cronExpression
}}</a-descriptions-item>
<a-descriptions-item label="任务开始时间:">{{ formData.startTime }}</a-descriptions-item>
<a-descriptions-item label="任务结束时间:">{{ formData.endTime }}</a-descriptions-item>
</a-descriptions>
<template #footer>
<span class="dialog-footer">
<a-button @click="dialogClose">关闭</a-button>
</span>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import { getJobLogDetail } from '@/api/monitor/job';
import { onMounted, reactive, shallowRef } from 'vue';
const formData = reactive({
id: '',
jobName: '',
jobGroup: '',
jobTrigger: '',
jobMessage: '',
cronExpression: '',
startTime: '',
endTime: '',
});
const emit = defineEmits(['update:visible']);
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
logId: {
type: Number,
required: true,
default: 0,
},
});
const dialogClose = () => {
emit('update:visible', false);
};
const setFormData = async () => {
const data = await getJobLogDetail(props.logId);
for (const key in formData) {
if (data[key] != null && data[key] != undefined) {
//@ts-ignore
formData[key] = data[key];
}
}
};
const getReviceType = (type) => {
let typeText = '';
switch (type) {
case 1:
typeText = '系统用户';
break;
case 2:
typeText = '会员用户';
break;
case 3:
typeText = '其他';
break;
default:
break;
}
return typeText;
};
const getTyepText = (type) => {
let typeText = '';
switch (type) {
case 1:
typeText = '登录';
break;
case 2:
typeText = '注册';
break;
case 3:
typeText = '找回密码';
break;
case 4:
typeText = '业务';
break;
case 5:
typeText = '其他';
break;
default:
break;
}
return typeText;
};
onMounted(() => {
if (props.logId) {
setFormData();
}
});
</script>

View File

@ -1,9 +0,0 @@
export type ComponentType =
| 'Input'
| 'InputNumber'
| 'Select'
| 'Checkbox'
| 'Switch'
| 'DatePicker'
| 'TimePicker'
| 'Cascader';

Some files were not shown because too many files have changed in this diff Show More