wip: 临时提交
This commit is contained in:
@@ -1,324 +0,0 @@
|
||||
<template>
|
||||
<view class="work">
|
||||
<!-- 筛选 -->
|
||||
<wd-drop-menu close-on-click-modal class="mb-20rpx mr-20rpx ml-20rpx">
|
||||
<wd-drop-menu-item ref="dropMenu" title="筛选" icon="filter" icon-size="18px">
|
||||
<view>
|
||||
<wd-input
|
||||
v-model="queryParams.keywords"
|
||||
label="关键字"
|
||||
type="text"
|
||||
clearable
|
||||
placeholder="请输入关键字"
|
||||
/>
|
||||
<view class="flex flex-row items-center mb-20rpx">
|
||||
<wd-button class="mt-20rpx mb-20rpx" size="medium" @click="handleQuery()">
|
||||
查询
|
||||
</wd-button>
|
||||
<wd-button size="medium" type="info" @click="handleReset">重置</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</wd-drop-menu-item>
|
||||
</wd-drop-menu>
|
||||
|
||||
<view class="data-container">
|
||||
<!-- 列表内容 -->
|
||||
<view v-for="(item, index) in pageData" :key="index" class="mb-20rpx">
|
||||
<wd-card>
|
||||
<template #title>
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="flex-1 text-truncate">{{ item.configName }}</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<wd-cell-group>
|
||||
<wd-cell title="配置键" :value="item.configKey" />
|
||||
<wd-cell title="配置值" :value="item.configValue" />
|
||||
<wd-cell title="备注" :value="item.remark" />
|
||||
</wd-cell-group>
|
||||
|
||||
<template #footer>
|
||||
<wd-button size="small" plain type="primary" @click="handleAction(item)">
|
||||
操作
|
||||
</wd-button>
|
||||
</template>
|
||||
</wd-card>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
<wd-loadmore :state="state" @reload="handleQuery" />
|
||||
|
||||
<!-- 底部按钮 -->
|
||||
<view class="fixed bottom-0 w-full flex justify-around items-center p-20rpx bg-#fff">
|
||||
<wd-button size="medium" type="primary" @click="handleOpenDialog">添加</wd-button>
|
||||
<wd-button size="medium" type="success" @click="refreshCache">刷新缓存</wd-button>
|
||||
</view>
|
||||
|
||||
<wd-popup v-model="showEditPopup" position="bottom">
|
||||
<view class="p-20rpx">
|
||||
<wd-form ref="formRef" :model="form">
|
||||
<wd-input
|
||||
v-model="form.configName"
|
||||
label="配置名称"
|
||||
type="text"
|
||||
placeholder="请输入配置名称"
|
||||
:rules="[{ required: true, message: '请填写配置名称' }]"
|
||||
/>
|
||||
<wd-input
|
||||
v-model="form.configKey"
|
||||
label="配置键名"
|
||||
type="text"
|
||||
placeholder="请输入配置键名"
|
||||
:rules="[{ required: true, message: '请填写配置键' }]"
|
||||
/>
|
||||
<wd-input
|
||||
v-model="form.configValue"
|
||||
label="配置键值"
|
||||
type="text"
|
||||
placeholder="请输入配置键值"
|
||||
:rules="[{ required: true, message: '请填写配置值' }]"
|
||||
/>
|
||||
<wd-textarea
|
||||
v-model="form.remark"
|
||||
prop="remark"
|
||||
label="配置描述"
|
||||
label-align="right"
|
||||
clearable
|
||||
:maxlength="100"
|
||||
show-word-limit
|
||||
label-width="100px"
|
||||
placeholder="请输入配置描述"
|
||||
/>
|
||||
</wd-form>
|
||||
<view class="flex justify-around mt-20rpx">
|
||||
<wd-button @click="showEditPopup = false">取消</wd-button>
|
||||
<wd-button type="primary" native-type="submit" :loading="loading" @click="submitForm">
|
||||
确定
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</wd-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ConfigAPI, { ConfigPageVO, ConfigForm, ConfigPageQuery } from "@/api/system/config";
|
||||
import { DropMenuItemExpose } from "wot-design-uni/components/wd-drop-menu-item/types";
|
||||
import { LoadMoreState } from "wot-design-uni/components/wd-loadmore/types";
|
||||
import { FormInstance } from "wot-design-uni/components/wd-form/types";
|
||||
import { debounce } from "@/utils";
|
||||
const state = ref<LoadMoreState>("loading"); // 加载状态 loading, finished:, error
|
||||
const total = ref(0);
|
||||
const queryParams = reactive<ConfigPageQuery>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
keywords: "",
|
||||
});
|
||||
// 系统配置表格数据
|
||||
const pageData = ref<ConfigPageVO[]>([]);
|
||||
const formRef = ref<FormInstance>();
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
/**
|
||||
* 搜索栏
|
||||
*/
|
||||
const dropMenu = ref<DropMenuItemExpose>();
|
||||
|
||||
/**
|
||||
* 搜索
|
||||
*/
|
||||
function handleQuery() {
|
||||
pageData.value = [];
|
||||
dropMenu.value?.close();
|
||||
queryParams.pageNum = 1;
|
||||
loadmore();
|
||||
}
|
||||
|
||||
const showEditPopup = ref(false);
|
||||
const form = ref<ConfigForm>({});
|
||||
|
||||
// 修改编辑函数
|
||||
function handleEdit(id: number) {
|
||||
ConfigAPI.getFormData(id).then((data) => {
|
||||
Object.assign(form.value, data);
|
||||
// 显示弹窗
|
||||
showEditPopup.value = true;
|
||||
});
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
async function submitForm() {
|
||||
loading.value = true;
|
||||
try {
|
||||
if (formRef.value) {
|
||||
formRef.value!.validate().then(async ({ valid }) => {
|
||||
if (valid) {
|
||||
if (form.value.id) {
|
||||
await ConfigAPI.update(form.value.id, form.value);
|
||||
uni.showToast({ title: "更新成功", icon: "success" });
|
||||
} else {
|
||||
await ConfigAPI.add(form.value);
|
||||
uni.showToast({ title: "添加成功", icon: "success" });
|
||||
}
|
||||
showEditPopup.value = false;
|
||||
handleQuery(); // 刷新列表
|
||||
} else {
|
||||
uni.showToast({ title: "请检查表单", icon: "error" });
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
uni.showToast({ title: "操作失败", icon: "error" });
|
||||
loading.value = false;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置搜索条件
|
||||
*/
|
||||
function handleReset() {
|
||||
queryParams.pageNum = 1;
|
||||
queryParams.keywords = "";
|
||||
pageData.value = [];
|
||||
dropMenu.value?.close();
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* 触底事件
|
||||
*/
|
||||
onReachBottom(() => {
|
||||
queryParams.pageNum++;
|
||||
handleQuery();
|
||||
});
|
||||
|
||||
/**
|
||||
* 加载更多
|
||||
*/
|
||||
function loadmore() {
|
||||
state.value = "loading";
|
||||
ConfigAPI.getPage(queryParams)
|
||||
.then((data) => {
|
||||
if (queryParams.pageNum === 1) {
|
||||
pageData.value = data.list;
|
||||
} else {
|
||||
pageData.value.push(...data.list);
|
||||
}
|
||||
total.value = data.total;
|
||||
})
|
||||
.finally(() => {
|
||||
state.value = "finished";
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加
|
||||
*/
|
||||
function handleOpenDialog() {
|
||||
form.value.id = undefined;
|
||||
form.value.configName = "";
|
||||
form.value.configKey = "";
|
||||
form.value.configValue = "";
|
||||
form.value.remark = "";
|
||||
showEditPopup.value = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新缓存
|
||||
*/
|
||||
const refreshCache = debounce(() => {
|
||||
ConfigAPI.refreshCache().then(() => {
|
||||
uni.showToast({
|
||||
title: "刷新缓存成功",
|
||||
icon: "success",
|
||||
duration: 1000, // 显示时间,单位为毫秒,设置为 0 则不会自动消失
|
||||
});
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
function handleDelete(item: ConfigPageVO) {
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "确定要删除该配置吗?",
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
if (item.id) {
|
||||
ConfigAPI.deleteById(item.id).then(() => {
|
||||
uni.showToast({ title: "删除成功", icon: "success" });
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作
|
||||
*/
|
||||
function handleAction(item: ConfigPageVO) {
|
||||
const actions = ["编辑", "删除"];
|
||||
uni.showActionSheet({
|
||||
itemList: actions,
|
||||
success: ({ tapIndex }) => {
|
||||
switch (actions[tapIndex]) {
|
||||
case "编辑":
|
||||
handleEdit(item.id || 0);
|
||||
break;
|
||||
case "删除":
|
||||
handleDelete(item);
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
handleQuery();
|
||||
});
|
||||
|
||||
/**
|
||||
* 页面返回回来也要重新加载数据
|
||||
*/
|
||||
onLoad(() => {
|
||||
queryParams.pageNum = 1;
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.data-container {
|
||||
:deep(.wd-cell__wrapper) {
|
||||
padding: 4rpx 0;
|
||||
}
|
||||
|
||||
:deep(.wd-cell) {
|
||||
padding-right: 10rpx;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
:deep(.wd-fab__trigger) {
|
||||
width: 80rpx !important;
|
||||
height: 80rpx !important;
|
||||
}
|
||||
|
||||
:deep(.wd-cell__right) {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
padding: 10rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.data-container {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,81 +0,0 @@
|
||||
<template>
|
||||
<view class="work">
|
||||
<template v-for="(item, index) in gridList" :key="index">
|
||||
<wd-card :title="item.title">
|
||||
<wd-grid clickable :column="4">
|
||||
<wd-grid-item
|
||||
v-for="(child, index) in item.children"
|
||||
:key="index"
|
||||
:v-has-perm="child.prem"
|
||||
use-slot
|
||||
link-type="navigateTo"
|
||||
:url="child.url"
|
||||
>
|
||||
<view class="p-2">
|
||||
<image class="w-72rpx h-72rpx rounded-8rpx" :src="child.icon" />
|
||||
</view>
|
||||
<view class="text">{{ child.title }}</view>
|
||||
</wd-grid-item>
|
||||
</wd-grid>
|
||||
</wd-card>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const gridList = reactive([
|
||||
{
|
||||
title: "系统管理",
|
||||
children: [
|
||||
{
|
||||
icon: "/static/icons/user.png",
|
||||
title: "用户管理",
|
||||
url: "/pages/work/user/index",
|
||||
prem: "sys:user:query",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/role.png",
|
||||
title: "角色管理",
|
||||
url: "/pages/work/role/index",
|
||||
prem: "sys:role:query",
|
||||
},
|
||||
|
||||
{
|
||||
icon: "/static/icons/notice.png",
|
||||
title: "通知公告",
|
||||
url: "/pages/work/notice/index",
|
||||
prem: "sys:notice:query",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/setting.png",
|
||||
title: "系统配置",
|
||||
url: "/pages/work/config/index",
|
||||
prem: "sys:config:query",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "系统监控",
|
||||
children: [
|
||||
{
|
||||
icon: "/static/icons/log.png",
|
||||
title: "系统日志",
|
||||
url: "/pages/work/log/index",
|
||||
prem: "sys:log:query",
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* stylelint-disable selector-type-no-unknown */
|
||||
page {
|
||||
background: #f8f8f8;
|
||||
}
|
||||
/* stylelint-enable selector-type-no-unknown */
|
||||
|
||||
.work {
|
||||
padding: 40rpx 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,174 +0,0 @@
|
||||
<template>
|
||||
<view class="log">
|
||||
<!-- 筛选 -->
|
||||
<wd-drop-menu close-on-click-modal class="mb-24rpx">
|
||||
<wd-drop-menu-item ref="filterDropMenu" title="筛选" icon="filter" icon-size="18px">
|
||||
<view>
|
||||
<wd-input
|
||||
v-model="queryParams.keywords"
|
||||
label="关键字"
|
||||
type="text"
|
||||
placeholder="请输入关键字"
|
||||
/>
|
||||
|
||||
<cu-date-query v-model="queryParams.createTime" :label="'日期选择'" />
|
||||
|
||||
<view class="flex-between py-2">
|
||||
<wd-button class="w-20%" type="info" @click="handleResetQuery">重置</wd-button>
|
||||
<wd-button class="w-70%" @click="handleQuery">查询</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</wd-drop-menu-item>
|
||||
</wd-drop-menu>
|
||||
|
||||
<!-- 卡片列表 -->
|
||||
<wd-card v-for="item in pageData" :key="item.id" class="card-list">
|
||||
<template #title>
|
||||
{{ item.operator }}
|
||||
</template>
|
||||
|
||||
<wd-cell-group>
|
||||
<wd-cell title="模块" :value="item.module" />
|
||||
<wd-cell title="内容" :value="item.content" />
|
||||
<wd-cell title="IP" :value="item.ip" />
|
||||
<wd-cell title="地区" :value="item.region" />
|
||||
</wd-cell-group>
|
||||
|
||||
<template #footer>
|
||||
<view class="flex-between">
|
||||
<view class="text-left">
|
||||
<wd-text text="创建时间:" size="small" class="font-bold" />
|
||||
<wd-text :text="item.createTime" size="small" />
|
||||
</view>
|
||||
<view class="text-right">
|
||||
<wd-button type="primary" size="small" plain @click="handleViewDetail(item)">
|
||||
查看详情
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</wd-card>
|
||||
|
||||
<!-- 详情弹窗 -->
|
||||
<wd-popup v-model="detailDialogVisible" position="bottom">
|
||||
<wd-cell-group>
|
||||
<wd-cell title="操作人" :value="logDetail.operator" />
|
||||
<wd-cell title="操作时间" :value="logDetail.createTime" />
|
||||
<wd-cell title="模块" :value="logDetail.module" />
|
||||
<wd-cell title="内容" :value="logDetail.content" />
|
||||
<wd-cell title="IP" :value="logDetail.ip" />
|
||||
<wd-cell title="地区" :value="logDetail.region" />
|
||||
<wd-cell title="浏览器" :value="logDetail.region" />
|
||||
<wd-cell title="终端系统" :value="logDetail.os" />
|
||||
<wd-cell title="耗时(毫秒)" :value="logDetail.executionTime" />
|
||||
</wd-cell-group>
|
||||
</wd-popup>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
<wd-loadmore v-if="total > 0" :state="loadMoreState" @reload="loadmore" />
|
||||
<wd-status-tip v-else-if="total == 0" image="search" tip="当前搜索无结果" />
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onLoad, onReachBottom } from "@dcloudio/uni-app";
|
||||
import { LoadMoreState } from "wot-design-uni/components/wd-loadmore/types";
|
||||
import { DropMenuItemExpose } from "wot-design-uni/components/wd-drop-menu-item/types";
|
||||
|
||||
import LogAPI, { LogVO, LogPageQuery } from "@/api/system/log";
|
||||
|
||||
const filterDropMenu = ref<DropMenuItemExpose>();
|
||||
const loadMoreState = ref<LoadMoreState>("loading");
|
||||
|
||||
const queryParams = reactive<LogPageQuery>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
});
|
||||
|
||||
const total = ref(0);
|
||||
const pageData = ref<LogVO[]>([]);
|
||||
|
||||
const logDetail = ref<LogVO>({});
|
||||
const detailDialogVisible = ref(false);
|
||||
|
||||
/**
|
||||
* 搜索栏
|
||||
*/
|
||||
function handleQuery() {
|
||||
filterDropMenu.value?.close();
|
||||
queryParams.pageNum = 1;
|
||||
loadmore();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置搜索
|
||||
*/
|
||||
function handleResetQuery() {
|
||||
queryParams.keywords = undefined;
|
||||
queryParams.createTime = undefined;
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载更多
|
||||
*/
|
||||
function loadmore() {
|
||||
loadMoreState.value = "loading";
|
||||
LogAPI.getPage(queryParams)
|
||||
.then((data) => {
|
||||
pageData.value = data.list;
|
||||
total.value = data.total;
|
||||
queryParams.pageNum++;
|
||||
})
|
||||
.catch(() => {
|
||||
pageData.value = [];
|
||||
})
|
||||
.finally(() => {
|
||||
loadMoreState.value = "finished";
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看详情
|
||||
*/
|
||||
function handleViewDetail(item: LogVO) {
|
||||
detailDialogVisible.value = true;
|
||||
logDetail.value = item;
|
||||
}
|
||||
|
||||
/**
|
||||
* 触底事件
|
||||
*/
|
||||
onReachBottom(() => {
|
||||
if (queryParams.pageNum * queryParams.pageSize < total.value) {
|
||||
loadmore();
|
||||
} else if (queryParams.pageNum * queryParams.pageSize >= total.value) {
|
||||
loadMoreState.value = "finished";
|
||||
}
|
||||
});
|
||||
|
||||
onLoad(() => {
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.wd-col {
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
::v-deep .wd-drop-menu__item {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 0 50rpx;
|
||||
}
|
||||
|
||||
.card-list {
|
||||
:deep(.wd-cell__wrapper) {
|
||||
padding: 4rpx 0;
|
||||
}
|
||||
:deep(.wd-cell) {
|
||||
padding-right: 10rpx;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,117 +0,0 @@
|
||||
<template>
|
||||
<div class="notice-detail">
|
||||
<wd-cell-group>
|
||||
<div class="notice-header">
|
||||
<h2 class="notice-title">
|
||||
<wd-icon name="prompt" size="20px" class="title-icon" />
|
||||
{{ noticeDetail.title }}
|
||||
</h2>
|
||||
<div class="notice-meta">
|
||||
<div class="meta-row">
|
||||
优先级:
|
||||
<cu-dict-label code="notice_level" :model-value="noticeDetail.level" />
|
||||
</div>
|
||||
<div class="meta-row">发布人:{{ noticeDetail.publisherName }}</div>
|
||||
<div class="meta-row">发布时间:{{ noticeDetail.publishTime }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<wd-divider />
|
||||
<div class="notice-content" v-html="noticeDetail.content" />
|
||||
</wd-cell-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import NoticeAPI, { NoticeDetailVO } from "@/api/system/notice";
|
||||
|
||||
const noticeDetail = ref<NoticeDetailVO>({});
|
||||
|
||||
/**
|
||||
* 获取通知详情
|
||||
* @param id 通知ID
|
||||
*/
|
||||
const getNoticeDetail = async (id: string) => {
|
||||
try {
|
||||
const res = await NoticeAPI.getDetail(id);
|
||||
noticeDetail.value = res;
|
||||
} catch (error) {
|
||||
console.error("获取通知详情失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// 页面加载
|
||||
onLoad((options: any) => {
|
||||
if (options && options.id) {
|
||||
getNoticeDetail(options.id as string);
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: "通知不存在",
|
||||
icon: "none",
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.notice-detail {
|
||||
padding: 12px;
|
||||
background: #f7f8fa;
|
||||
}
|
||||
|
||||
.notice-header {
|
||||
padding: 16px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.notice-title {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 12px;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.title-icon {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.notice-meta {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.meta-row {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.priority-wrapper {
|
||||
display: inline-flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.notice-content {
|
||||
padding: 16px;
|
||||
font-size: 15px;
|
||||
line-height: 1.6;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
:deep(.wd-divider) {
|
||||
margin: 0 8px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,284 +0,0 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 添加搜索栏 -->
|
||||
<wd-drop-menu close-on-click-modal class="mb-20rpx mr-20rpx ml-20rpx">
|
||||
<wd-drop-menu-item ref="dropMenu" title="筛选" icon="filter" icon-size="18px">
|
||||
<view>
|
||||
<wd-input
|
||||
v-model="queryParams.title"
|
||||
label="关键字"
|
||||
type="text"
|
||||
placeholder="请输入关键字"
|
||||
/>
|
||||
|
||||
<view class="flex flex-row items-center mb-20rpx">
|
||||
<wd-button class="mt-20rpx mb-20rpx" size="medium" @click="handleQuery()">
|
||||
查询
|
||||
</wd-button>
|
||||
<wd-button size="medium" type="info" @click="handleReset">重置</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</wd-drop-menu-item>
|
||||
</wd-drop-menu>
|
||||
|
||||
<!-- 列表内容 -->
|
||||
<view class="data-container">
|
||||
<view v-for="(item, index) in dataList" :key="index" class="mt-20rpx">
|
||||
<wd-card>
|
||||
<template #title>
|
||||
<view class="flex items-center justify-between">
|
||||
<view class="flex-1 text-truncate">{{ item.title }}</view>
|
||||
<wd-tag :type="getStatusType(item.publishStatus)" size="small">
|
||||
{{ getStatusText(item.publishStatus) }}
|
||||
</wd-tag>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<wd-cell-group>
|
||||
<wd-cell title="通告目标类型" :value="item.targetType === 1 ? '指定' : '全体'" />
|
||||
<wd-cell title="紧急程度">
|
||||
<template #default>
|
||||
<cu-dict-label code="notice_level" :model-value="item.level" />
|
||||
</template>
|
||||
</wd-cell>
|
||||
<wd-cell title="发布人" :value="item.publisherName || '-'" />
|
||||
</wd-cell-group>
|
||||
<template #footer>
|
||||
<view class="flex-between">
|
||||
<view v-if="item.publishStatus === 1" class="text-left">
|
||||
<wd-text text="发布时间:" size="small" class="font-bold" />
|
||||
<wd-text :text="formatDate(item.publishTime)" size="small" />
|
||||
</view>
|
||||
<view v-else class="text-left">
|
||||
<wd-text text="撤回时间:" size="small" class="font-bold" />
|
||||
<wd-text :text="formatDate(item.revokeTime)" size="small" />
|
||||
</view>
|
||||
<view class="text-right">
|
||||
<wd-button size="small" plain type="primary" @click="handleAction(item)">
|
||||
操作
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</wd-card>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
<wd-loadmore custom-class="loadmore" :state="loadState" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { LoadMoreState } from "wot-design-uni/components/wd-loadmore/types";
|
||||
import { DropMenuItemExpose } from "wot-design-uni/components/wd-drop-menu-item/types";
|
||||
import NoticeAPI, { NoticePageQuery, NoticePageVO } from "@/api/system/notice";
|
||||
const loadState = ref<LoadMoreState>("finished");
|
||||
const dataList = ref<NoticePageVO[]>([]);
|
||||
const total = ref(0);
|
||||
|
||||
// 修改查询参数
|
||||
const queryParams = ref<NoticePageQuery>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
title: "",
|
||||
});
|
||||
|
||||
// 添加搜索处理函数
|
||||
const dropMenu = ref<DropMenuItemExpose>();
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
loadMore();
|
||||
dropMenu.value?.close();
|
||||
};
|
||||
|
||||
// 重置
|
||||
const handleReset = () => {
|
||||
queryParams.value = { pageNum: 1, pageSize: 10 };
|
||||
dropMenu.value?.close();
|
||||
loadMore();
|
||||
};
|
||||
|
||||
// 获取状态样式
|
||||
const getStatusType = (
|
||||
status: number | undefined
|
||||
): "default" | "primary" | "danger" | "warning" | "success" => {
|
||||
if (!status) return "default";
|
||||
const statusMap: Record<number, "default" | "primary" | "danger" | "warning" | "success"> = {
|
||||
0: "primary",
|
||||
1: "success",
|
||||
[-1]: "warning",
|
||||
};
|
||||
return statusMap[status] || "default";
|
||||
};
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status: number | undefined): string => {
|
||||
if (status !== 0 && !status) return "-";
|
||||
const statusMap: Record<number, string> = {
|
||||
0: "未发布",
|
||||
1: "已发布",
|
||||
[-1]: "已撤回",
|
||||
};
|
||||
return statusMap[status] || "未知";
|
||||
};
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (date: Date | undefined): string => {
|
||||
return date ? date.toString() : "-";
|
||||
};
|
||||
|
||||
// 加载更多
|
||||
const loadMore = async () => {
|
||||
if (loadState.value === "loading") return;
|
||||
|
||||
loadState.value = "loading";
|
||||
const { list, total: totalCount } = await NoticeAPI.getPage(queryParams.value);
|
||||
|
||||
if (queryParams.value.pageNum === 1) {
|
||||
dataList.value = list;
|
||||
} else {
|
||||
dataList.value = [...dataList.value, ...list];
|
||||
}
|
||||
|
||||
total.value = totalCount;
|
||||
queryParams.value.pageNum++;
|
||||
|
||||
loadState.value = dataList.value.length >= total.value ? "finished" : "loading";
|
||||
};
|
||||
|
||||
// 查看详情
|
||||
const handleView = (notice: NoticePageVO) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/work/notice/detail?id=${notice.id}`,
|
||||
});
|
||||
};
|
||||
|
||||
// 操作按钮
|
||||
const handleAction = (notice: NoticePageVO) => {
|
||||
const actions = notice.publishStatus !== 1 ? ["查看", "删除", "发布"] : ["查看", "撤回"];
|
||||
uni.showActionSheet({
|
||||
itemList: actions,
|
||||
success: ({ tapIndex }) => {
|
||||
switch (actions[tapIndex]) {
|
||||
case "查看":
|
||||
handleView(notice);
|
||||
break;
|
||||
case "删除":
|
||||
handleDelete(notice);
|
||||
break;
|
||||
case "发布":
|
||||
handlePublish(notice);
|
||||
break;
|
||||
case "撤回":
|
||||
handleRevoke(notice);
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 删除
|
||||
const handleDelete = (notice: NoticePageVO) => {
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "确定要删除该通知吗?",
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
await NoticeAPI.deleteByIds(notice.id);
|
||||
uni.showToast({ title: "删除成功", icon: "success" });
|
||||
// 重新加载第一页
|
||||
queryParams.value.pageNum = 1;
|
||||
loadMore();
|
||||
} catch (error) {
|
||||
uni.showToast({ title: "删除失败" + error, icon: "none" });
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 发布
|
||||
const handlePublish = (notice: NoticePageVO) => {
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "确定要发布该通知吗?",
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
await NoticeAPI.publish(Number(notice.id));
|
||||
uni.showToast({ title: "发布成功", icon: "success" });
|
||||
// 重新加载第一页
|
||||
queryParams.value.pageNum = 1;
|
||||
loadMore();
|
||||
} catch (error) {
|
||||
uni.showToast({ title: "发布失败" + error, icon: "none" });
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 撤回
|
||||
const handleRevoke = (notice: NoticePageVO) => {
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "确定要撤回该通知吗?",
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
await NoticeAPI.revoke(Number(notice.id));
|
||||
uni.showToast({
|
||||
title: "撤回成功",
|
||||
icon: "success",
|
||||
});
|
||||
// 刷新列表
|
||||
queryParams.value.pageNum = 1;
|
||||
loadMore();
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: "撤回失败" + error,
|
||||
icon: "error",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
onReachBottom(() => {
|
||||
if (loadState.value === "loading" || loadState.value === "finished") return;
|
||||
loadMore();
|
||||
});
|
||||
|
||||
onLoad(() => {
|
||||
loadMore();
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.data-container {
|
||||
:deep(.wd-cell__wrapper) {
|
||||
padding: 4rpx 0;
|
||||
}
|
||||
|
||||
:deep(.wd-cell) {
|
||||
padding-right: 10rpx;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
:deep(.wd-fab__trigger) {
|
||||
width: 80rpx !important;
|
||||
height: 80rpx !important;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
padding: 10rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.data-container {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,109 +0,0 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="p-l-8 p-b-20">
|
||||
<DaTree
|
||||
ref="DaTreeRef"
|
||||
:data="menuPermOptions"
|
||||
:defaultExpandAll="true"
|
||||
:showCheckbox="true"
|
||||
/>
|
||||
</view>
|
||||
<wd-fab v-model:active="showFab" type="primary" position="right-top" direction="bottom">
|
||||
<wd-button custom-class="custom-button" type="primary" @click="doCheckedTree(rootKeys, true)">
|
||||
全 选
|
||||
</wd-button>
|
||||
<wd-button custom-class="custom-button" type="error" @click="doCheckedTree(rootKeys, false)">
|
||||
全不选
|
||||
</wd-button>
|
||||
<wd-button custom-class="custom-button" type="success" @click="doExpandTree('all', true)">
|
||||
全展开
|
||||
</wd-button>
|
||||
<wd-button custom-class="custom-button" type="warning" @click="doExpandTree('all', false)">
|
||||
全收起
|
||||
</wd-button>
|
||||
</wd-fab>
|
||||
<!-- 底部按钮 -->
|
||||
<view class="footer-buttons" style="">
|
||||
<wd-button size="medium" type="primary" block @click="handleAssignPermSubmit">
|
||||
确 定
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import RoleAPI from "@/api/system/role";
|
||||
import MenuAPI from "@/api/system/menu";
|
||||
import DaTree from "@/components/da-tree/index.vue";
|
||||
|
||||
let roleId = ref<number>(); // 操作的角色ID
|
||||
const menuPermOptions = ref<OptionType[]>([]); // 所有菜单
|
||||
let rootKeys = ref<number[]>([]); // 根节点数组
|
||||
const DaTreeRef = ref(); // 树引用
|
||||
const showFab = ref(); // 悬浮按钮是否展开
|
||||
|
||||
/**
|
||||
* 分配菜单权限页面数据初始化
|
||||
*/
|
||||
async function initAssignPerm() {
|
||||
// 获取所有的菜单
|
||||
menuPermOptions.value = await MenuAPI.getOptions(false);
|
||||
rootKeys.value = menuPermOptions.value.map((item) => item.value as number);
|
||||
// 回显角色已拥有的菜单
|
||||
RoleAPI.getRoleMenuIds(roleId.value!).then((data) => {
|
||||
const checkedMenuIds = data;
|
||||
if (checkedMenuIds && checkedMenuIds.length > 0) {
|
||||
DaTreeRef.value?.setCheckedKeys(checkedMenuIds, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 展开/收起树节点
|
||||
function doExpandTree(keys: number[] | string, expand: boolean) {
|
||||
DaTreeRef.value?.setExpandedKeys(keys, expand);
|
||||
showFab.value = false;
|
||||
}
|
||||
// 选中/取消树节点
|
||||
function doCheckedTree(keys: number[], checked: boolean) {
|
||||
DaTreeRef.value?.setCheckedKeys(keys, checked);
|
||||
showFab.value = false;
|
||||
}
|
||||
|
||||
// 分配菜单权限提交
|
||||
function handleAssignPermSubmit() {
|
||||
if (roleId.value) {
|
||||
const checkedMenuIds: number[] = DaTreeRef.value?.getCheckedKeys();
|
||||
RoleAPI.updateRoleMenus(roleId.value, checkedMenuIds).then(() => {
|
||||
uni.showToast({ title: "分配权限成功", icon: "success" });
|
||||
uni.navigateBack({ delta: 1 });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onLoad((options: any) => {
|
||||
if (options && options.id) {
|
||||
roleId.value = options.id;
|
||||
}
|
||||
initAssignPerm();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.footer-buttons {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
padding: 20rpx;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
:deep(.custom-button) {
|
||||
box-sizing: border-box;
|
||||
width: 64px !important;
|
||||
min-width: auto !important;
|
||||
height: 32px !important;
|
||||
margin: 8rpx;
|
||||
border-radius: 16px !important;
|
||||
}
|
||||
</style>
|
||||
@@ -1,356 +0,0 @@
|
||||
<template>
|
||||
<view class="role">
|
||||
<!-- 筛选 -->
|
||||
<wd-drop-menu>
|
||||
<wd-drop-menu-item ref="filterDropMenu" icon="filter" icon-size="18px" title="筛选">
|
||||
<view>
|
||||
<wd-input
|
||||
v-model="queryParams.keywords"
|
||||
label="关键字"
|
||||
type="text"
|
||||
placeholder="请输入关键字"
|
||||
/>
|
||||
<view class="flex-between py-2">
|
||||
<wd-button custom-class="w-20%" type="info" @click="handleResetQuery">重置</wd-button>
|
||||
<wd-button custom-class="w-70%" @click="handleQuery">确定</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</wd-drop-menu-item>
|
||||
</wd-drop-menu>
|
||||
<!-- 卡片列表 -->
|
||||
<view class="list-container">
|
||||
<wd-card v-for="item in dataList" :key="item.id" class="role-card">
|
||||
<template #title>
|
||||
<view class="flex-between">
|
||||
<view class="flex-center">
|
||||
<view class="ml-2">
|
||||
<view class="font-bold">
|
||||
{{ item.name }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<wd-tag v-if="item.status === 1" type="success" plain>正常</wd-tag>
|
||||
<wd-tag v-else-if="item.status === 0" plain>停用</wd-tag>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<wd-cell-group>
|
||||
<wd-cell title="编码" title-width="150rpx" :value="item.code" />
|
||||
<wd-cell title="排序号" title-width="150rpx" :value="item.sort" />
|
||||
</wd-cell-group>
|
||||
|
||||
<template #footer>
|
||||
<view class="flex-between">
|
||||
<view class="text-left">
|
||||
<wd-text text="创建时间:" size="small" class="font-bold" />
|
||||
<wd-text :text="item.createTime" size="small" />
|
||||
</view>
|
||||
<view class="flex-right">
|
||||
<wd-button size="small" plain @click="handleAction(item)">操作</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</wd-card>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
<wd-loadmore :state="loadMoreState" @reload="queryPageData" />
|
||||
</view>
|
||||
<!-- 底部按钮 -->
|
||||
<wd-fab
|
||||
position="left-bottom"
|
||||
:expandable="false"
|
||||
customStyle="width: 1rem; height: 1rem; line-height: 1rem;z-index:9"
|
||||
@click="handleOpenDialog()"
|
||||
/>
|
||||
|
||||
<wd-popup v-model="dialog.visible" position="bottom" custom-class="yl-popup">
|
||||
<wd-form ref="roleFormRef" :model="formData" :rules="rules">
|
||||
<wd-cell-group border>
|
||||
<wd-input v-model="formData.name" label="角色名称" prop="name" />
|
||||
<wd-input v-model="formData.code" label="角色编码" prop="code" />
|
||||
<wd-select-picker
|
||||
v-model="formData.dataScope"
|
||||
type="radio"
|
||||
label="数据权限"
|
||||
:columns="dataScopeOptions"
|
||||
:align-right="true"
|
||||
prop="dataScope"
|
||||
/>
|
||||
<wd-cell title="状态" prop="status">
|
||||
<wd-switch v-model="formData.status" :active-value="1" :inactive-value="0" />
|
||||
</wd-cell>
|
||||
<wd-cell title="排序" prop="sort">
|
||||
<wd-input-number v-model="formData.sort" />
|
||||
</wd-cell>
|
||||
</wd-cell-group>
|
||||
</wd-form>
|
||||
<view class="footer">
|
||||
<wd-button type="primary" block @click="handleSubmit">提交</wd-button>
|
||||
</view>
|
||||
</wd-popup>
|
||||
<wd-message-box />
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import RoleAPI, { RolePageVO, RolePageQuery, RoleForm } from "@/api/system/role";
|
||||
import { onLoad, onReachBottom } from "@dcloudio/uni-app";
|
||||
import { LoadMoreState } from "wot-design-uni/components/wd-loadmore/types";
|
||||
import { DropMenuItemExpose } from "wot-design-uni/components/wd-drop-menu-item/types";
|
||||
import { FormInstance } from "wot-design-uni/components/wd-form/types";
|
||||
import { FormRules } from "wot-design-uni/components/wd-form/types";
|
||||
import { useMessage } from "wot-design-uni";
|
||||
const message = useMessage();
|
||||
|
||||
const loadMoreState = ref<LoadMoreState>("loading");
|
||||
|
||||
const total = ref(0);
|
||||
|
||||
const queryParams = reactive<RolePageQuery>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
});
|
||||
|
||||
/**
|
||||
* 搜索栏
|
||||
*/
|
||||
const filterDropMenu = ref<DropMenuItemExpose>();
|
||||
|
||||
function handleQuery() {
|
||||
filterDropMenu.value?.close();
|
||||
queryParams.pageNum = 1;
|
||||
dataList.value = [];
|
||||
queryPageData();
|
||||
}
|
||||
/**
|
||||
* 重置查询
|
||||
*/
|
||||
const handleResetQuery = () => {
|
||||
filterDropMenu.value?.close();
|
||||
queryParams.keywords = "";
|
||||
queryParams.pageNum = 1;
|
||||
dataList.value = [];
|
||||
queryPageData();
|
||||
};
|
||||
|
||||
// 角色列表数据
|
||||
const dataList = ref<RolePageVO[]>([]);
|
||||
|
||||
/**
|
||||
* 查询分页数据
|
||||
*/
|
||||
function queryPageData() {
|
||||
loadMoreState.value = "loading";
|
||||
RoleAPI.getPage(queryParams)
|
||||
.then((data) => {
|
||||
dataList.value?.push(...data.list);
|
||||
total.value = data.total;
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log("系统异常", e);
|
||||
})
|
||||
.finally(() => {
|
||||
loadMoreState.value = "finished";
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 触底事件
|
||||
*/
|
||||
onReachBottom(() => {
|
||||
if (queryParams.pageNum * queryParams.pageSize < total.value) {
|
||||
queryParams.pageNum++;
|
||||
queryPageData();
|
||||
} else {
|
||||
loadMoreState.value = "finished";
|
||||
}
|
||||
});
|
||||
|
||||
// 操作按钮
|
||||
const handleAction = (item: RolePageVO) => {
|
||||
const actions = ["编辑", "分配权限", "删除"];
|
||||
uni.showActionSheet({
|
||||
itemList: actions,
|
||||
success: ({ tapIndex }) => {
|
||||
switch (actions[tapIndex]) {
|
||||
case "编辑":
|
||||
handleOpenDialog(item.id);
|
||||
break;
|
||||
case "分配权限":
|
||||
handleAssignPerm(item.id);
|
||||
break;
|
||||
case "删除":
|
||||
handleDelete(item.id);
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
});
|
||||
|
||||
const dataScopeOptions = ref<Record<string, any>[]>([
|
||||
{ label: "全部数据", value: 0 },
|
||||
{ label: "部门及子部门数据", value: 1 },
|
||||
{ label: "本部门数据", value: 2 },
|
||||
{ label: "本人数据", value: 3 },
|
||||
]);
|
||||
|
||||
const formData = reactive<RoleForm>({
|
||||
dataScope: 0,
|
||||
sort: 1,
|
||||
});
|
||||
|
||||
const rules: FormRules = {
|
||||
name: [{ required: true, message: "请输入角色名称", trigger: "blur" }],
|
||||
code: [{ required: true, message: "请输入角色编码", trigger: "blur" }],
|
||||
dataScope: [{ required: true, message: "请选择数据权限", trigger: "blur" }],
|
||||
status: [{ required: true, message: "请选择状态", trigger: "change" }],
|
||||
sort: [{ required: true, message: "请输入排序号", trigger: "change" }],
|
||||
};
|
||||
|
||||
const roleFormRef = ref<FormInstance>();
|
||||
|
||||
/**
|
||||
* 打开弹窗
|
||||
*/
|
||||
async function handleOpenDialog(id?: number) {
|
||||
dialog.visible = true;
|
||||
formData.id = undefined;
|
||||
formData.name = "";
|
||||
formData.code = "";
|
||||
formData.dataScope = 0;
|
||||
formData.status = 1;
|
||||
formData.sort = 1;
|
||||
if (id) {
|
||||
RoleAPI.getFormData(id).then((data) => {
|
||||
Object.assign(formData, { ...data });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交保存
|
||||
*/
|
||||
function handleSubmit() {
|
||||
if (roleFormRef.value) {
|
||||
roleFormRef.value.validate().then(({ valid }) => {
|
||||
if (valid) {
|
||||
const roleId = formData.id;
|
||||
if (roleId) {
|
||||
RoleAPI.update(roleId, formData).then(() => {
|
||||
uni.showToast({ title: "修改成功", icon: "success" });
|
||||
dialog.visible = false;
|
||||
queryParams.pageNum = 1;
|
||||
handleQuery();
|
||||
});
|
||||
} else {
|
||||
RoleAPI.add(formData).then(() => {
|
||||
uni.showToast({ title: "添加成功", icon: "success" });
|
||||
dialog.visible = false;
|
||||
queryParams.pageNum = 1;
|
||||
handleQuery();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*
|
||||
* @param id 用户id
|
||||
*/
|
||||
function handleDelete(id: number) {
|
||||
message
|
||||
.confirm({
|
||||
msg: "确认删除角色吗?",
|
||||
title: "提示",
|
||||
})
|
||||
.then(() => {
|
||||
RoleAPI.deleteByIds(id + "").then(() => {
|
||||
uni.showToast({ title: "删除成功", icon: "success" });
|
||||
queryParams.pageNum = 1;
|
||||
handleQuery();
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
console.log("点击了取消按钮");
|
||||
});
|
||||
}
|
||||
|
||||
function handleAssignPerm(id: number) {
|
||||
uni.navigateTo({
|
||||
url: "/pages/work/role/assign-perm?id=" + id,
|
||||
});
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
// https://wot-design-uni.pages.dev/guide/common-problems#%E5%B0%8F%E7%A8%8B%E5%BA%8F%E6%A0%B7%E5%BC%8F%E9%9A%94%E7%A6%BB
|
||||
export default {
|
||||
options: {
|
||||
styleIsolation: "shared",
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.role {
|
||||
:deep(.wd-drop-menu .wd-drop-menu__item) {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 0 50rpx;
|
||||
}
|
||||
.list-container {
|
||||
.role-card {
|
||||
margin-top: 20rpx;
|
||||
:deep(.wd-cell__wrapper) {
|
||||
padding: 4rpx 0;
|
||||
}
|
||||
:deep(.wd-cell) {
|
||||
padding-right: 10rpx;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.wd-cell__wrapper) {
|
||||
padding: 4rpx 0;
|
||||
}
|
||||
|
||||
:deep(.wd-cell) {
|
||||
padding-right: 10rpx;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
:deep(.wd-fab__trigger) {
|
||||
width: 80rpx !important;
|
||||
height: 80rpx !important;
|
||||
}
|
||||
.yl-popup {
|
||||
.footer {
|
||||
margin: 30rpx 0;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* wot组件直接写class,在小程序上无效
|
||||
* wot组件提供的custom-class属性也不能写unocss的写法
|
||||
* 故wot组件只能使用custom-class属性并在vue文件中自己写样式
|
||||
* 并且custom-class的类名需要使用:deep包裹,否则在小程序上也没有效果
|
||||
*/
|
||||
:deep(.w-20per) {
|
||||
width: 20%;
|
||||
}
|
||||
:deep(.w-70per) {
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,426 +0,0 @@
|
||||
<template>
|
||||
<!-- 自定义导航栏的占位 -->
|
||||
<view style="width: 100%; height: var(--status-bar-height)" />
|
||||
|
||||
<view class="user-container">
|
||||
<!-- 自定义导航栏 -->
|
||||
<wd-navbar title="用户管理">
|
||||
<template #left>
|
||||
<wd-icon name="thin-arrow-left" @click="handleNavigateback()" />
|
||||
</template>
|
||||
</wd-navbar>
|
||||
|
||||
<!-- 排序筛选 -->
|
||||
<view class="filter-container">
|
||||
<wd-drop-menu>
|
||||
<wd-drop-menu-item
|
||||
v-model="sortValue"
|
||||
:options="sortOptions"
|
||||
title="排序"
|
||||
icon="unfold-more"
|
||||
@change="handleSortChange"
|
||||
/>
|
||||
<wd-drop-menu-item ref="filterDropMenu" title="筛选" icon="filter">
|
||||
<view>
|
||||
<wd-input
|
||||
v-model="queryParams.keywords"
|
||||
label="关键字"
|
||||
placeholder="用户名/昵称/手机号"
|
||||
/>
|
||||
|
||||
<cu-date-query v-model="queryParams.createTime" label="创建时间" />
|
||||
|
||||
<view class="flex-between py-2">
|
||||
<wd-button type="info" @click="handleResetQuery">重置</wd-button>
|
||||
<wd-button @click="handleQuery">查询</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</wd-drop-menu-item>
|
||||
</wd-drop-menu>
|
||||
</view>
|
||||
|
||||
<!-- 数据列表 -->
|
||||
<view class="data-container">
|
||||
<wd-card v-for="item in pageData" :key="item.id">
|
||||
<template #title>
|
||||
<view class="flex-between">
|
||||
<view class="flex-center">
|
||||
<wd-img :width="50" :height="50" round :src="item.avatar" />
|
||||
<view class="ml-2">
|
||||
<view class="font-bold">
|
||||
{{ item.nickname }}
|
||||
<wd-icon v-if="item.gender == 1" name="gender-male" class="color-#4D80F0" />
|
||||
<wd-icon
|
||||
v-else-if="item.gender == 2"
|
||||
name="gender-female"
|
||||
class="color-#FA4350"
|
||||
/>
|
||||
</view>
|
||||
<view class="mt-1"><wd-text :text="item.deptName" size="12px" /></view>
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<wd-tag v-if="item.status === 1" type="success" plain>正常</wd-tag>
|
||||
<wd-tag v-else-if="item.status === 0" plain>禁用</wd-tag>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<wd-cell-group>
|
||||
<wd-cell title="用户名" :value="item.username" icon="user" />
|
||||
<wd-cell title="角色" :value="item.roleNames" icon="usergroup" />
|
||||
<wd-cell title="手机号码" :value="item.mobile" icon="mobile" />
|
||||
<wd-cell title="邮箱" :value="item.email" icon="mail" />
|
||||
</wd-cell-group>
|
||||
|
||||
<template #footer>
|
||||
<view class="flex-between">
|
||||
<view class="text-left">
|
||||
<wd-text text="创建时间:" size="small" class="font-bold" />
|
||||
<wd-text :text="item.createTime" size="small" />
|
||||
</view>
|
||||
<view class="text-right">
|
||||
<wd-button
|
||||
type="primary"
|
||||
size="small"
|
||||
plain
|
||||
:v-has-perm="'sys:user:edit'"
|
||||
@click="handleOpenDialog(item.id)"
|
||||
>
|
||||
编辑
|
||||
</wd-button>
|
||||
|
||||
<wd-button
|
||||
type="error"
|
||||
size="small"
|
||||
plain
|
||||
:v-has-perm="'sys:user:delete'"
|
||||
@click="handleDelete(item.id)"
|
||||
>
|
||||
删除
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</wd-card>
|
||||
|
||||
<wd-loadmore v-if="total > 0" :state="loadMoreState" @reload="loadmore" />
|
||||
<wd-status-tip v-else-if="total == 0" image="search" tip="当前搜索无结果" />
|
||||
</view>
|
||||
|
||||
<!-- 弹窗表单 -->
|
||||
<wd-popup v-model="dialog.visible" position="bottom" @close="hancleCloseDialog">
|
||||
<wd-form ref="userFormRef" :model="formData" :rules="rules">
|
||||
<wd-cell-group border>
|
||||
<wd-input v-model="formData.username" label="用户名" :readonly="!formData.id" required />
|
||||
<wd-input v-model="formData.nickname" label="昵称" required />
|
||||
<wd-select-picker
|
||||
v-model="formData.roleIds"
|
||||
label="角色"
|
||||
:columns="roleOptions"
|
||||
required
|
||||
/>
|
||||
<CuPicker
|
||||
v-model="formData.deptId"
|
||||
v-model:data="deptOptions"
|
||||
label="部门"
|
||||
:required="true"
|
||||
/>
|
||||
<wd-input v-model="formData.mobile" label="手机号" prop="mobile" />
|
||||
<wd-input v-model="formData.email" label="邮箱" prop="email" />
|
||||
<wd-cell title="状态">
|
||||
<wd-switch v-model="formData.status" :active-value="1" :inactive-value="0" required />
|
||||
</wd-cell>
|
||||
</wd-cell-group>
|
||||
</wd-form>
|
||||
<view class="popup-footer">
|
||||
<wd-button type="primary" block @click="handleSubmit">提交</wd-button>
|
||||
</view>
|
||||
</wd-popup>
|
||||
|
||||
<!-- 悬浮操作按钮 -->
|
||||
<wd-fab
|
||||
:v-has-perm="'sys:user:add'"
|
||||
position="left-bottom"
|
||||
:expandable="false"
|
||||
custom-style="z-index: 9"
|
||||
@click="handleOpenDialog"
|
||||
/>
|
||||
|
||||
<wd-message-box />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onLoad, onReachBottom } from "@dcloudio/uni-app";
|
||||
|
||||
import { LoadMoreState } from "wot-design-uni/components/wd-loadmore/types";
|
||||
import { FormRules } from "wot-design-uni/components/wd-form/types";
|
||||
import { useMessage } from "wot-design-uni";
|
||||
|
||||
import UserAPI, { type UserPageQuery, UserPageVO, UserForm } from "@/api/system/user";
|
||||
import RoleAPI from "@/api/system/role";
|
||||
import DeptAPI from "@/api/system/dept";
|
||||
|
||||
const message = useMessage();
|
||||
const loadMoreState = ref<LoadMoreState>("loading");
|
||||
const filterDropMenu = ref();
|
||||
const userFormRef = ref();
|
||||
|
||||
const sortValue = ref(0);
|
||||
const sortOptions = ref<Record<string, any>[]>([
|
||||
{ label: "默认排序", value: 0 },
|
||||
{ label: "最近创建", value: 1 },
|
||||
{ label: "最近更新", value: 2 },
|
||||
]);
|
||||
|
||||
let queryParams: UserPageQuery = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
|
||||
const total = ref(0);
|
||||
const pageData = ref<UserPageVO[]>([]);
|
||||
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
});
|
||||
|
||||
const initialFormData: UserForm = {
|
||||
id: undefined,
|
||||
roleIds: [],
|
||||
username: undefined,
|
||||
nickname: undefined,
|
||||
deptId: undefined,
|
||||
mobile: undefined,
|
||||
email: undefined,
|
||||
status: 1,
|
||||
};
|
||||
|
||||
const formData = reactive<UserForm>({ ...initialFormData });
|
||||
|
||||
const roleOptions = ref<Record<string, any>[]>([]);
|
||||
const deptOptions = ref<OptionType[]>([]);
|
||||
const rules: FormRules = {
|
||||
username: [{ required: true, message: "请输入用户名" }],
|
||||
nickname: [{ required: true, message: "请输入昵称" }],
|
||||
roleIds: [{ required: true, message: "请选择角色" }],
|
||||
deptId: [{ required: true, message: "请选择部门" }],
|
||||
status: [{ required: true, message: "请选择状态" }],
|
||||
mobile: [
|
||||
{
|
||||
required: false,
|
||||
message: "手机号格式不正确",
|
||||
validator: (value) => {
|
||||
if (!value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (!/^1[3456789]\d{9}$/.test(value)) {
|
||||
return Promise.reject("手机号格式不正确");
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
email: [
|
||||
{
|
||||
required: false,
|
||||
message: "邮箱格式不正确",
|
||||
validator: (value) => {
|
||||
if (!value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (!/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(value)) {
|
||||
return Promise.reject("邮箱格式不正确");
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
/**
|
||||
* 排序改变
|
||||
*/
|
||||
const handleSortChange = ({ value }: { value: number }) => {
|
||||
if (value === 1) {
|
||||
queryParams.field = "create_time";
|
||||
queryParams.direction = "DESC";
|
||||
} else if (value === 2) {
|
||||
queryParams.field = "update_time";
|
||||
queryParams.direction = "DESC";
|
||||
} else {
|
||||
queryParams.field = "";
|
||||
queryParams.direction = "";
|
||||
}
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询
|
||||
*/
|
||||
const handleQuery = () => {
|
||||
filterDropMenu.value?.close();
|
||||
queryParams.pageNum = 1;
|
||||
loadmore();
|
||||
console.log("queryParams", queryParams);
|
||||
};
|
||||
|
||||
/**
|
||||
* 重置查询
|
||||
*/
|
||||
const handleResetQuery = () => {
|
||||
queryParams = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
handleQuery();
|
||||
};
|
||||
|
||||
/**
|
||||
* 加载更多
|
||||
*/
|
||||
function loadmore() {
|
||||
loadMoreState.value = "loading";
|
||||
UserAPI.getPage(queryParams)
|
||||
.then((data) => {
|
||||
pageData.value = data.list;
|
||||
total.value = data.total;
|
||||
queryParams.pageNum++;
|
||||
})
|
||||
.catch((e) => {
|
||||
pageData.value = [];
|
||||
})
|
||||
.finally(() => {
|
||||
loadMoreState.value = "finished";
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开弹窗
|
||||
*/
|
||||
async function handleOpenDialog(id?: number) {
|
||||
dialog.visible = true;
|
||||
roleOptions.value = await RoleAPI.getOptions();
|
||||
deptOptions.value = await DeptAPI.getOptions();
|
||||
if (id) {
|
||||
UserAPI.getFormData(id).then((data) => {
|
||||
Object.assign(formData, { ...data });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交保存
|
||||
*/
|
||||
function handleSubmit() {
|
||||
hancleCloseDialog();
|
||||
userFormRef.value.validate().then(({ valid }: { valid: boolean }) => {
|
||||
if (valid) {
|
||||
const userId = formData.id;
|
||||
if (userId) {
|
||||
UserAPI.update(userId, formData).then(() => {
|
||||
message.show("修改成功");
|
||||
hancleCloseDialog();
|
||||
handleQuery();
|
||||
});
|
||||
} else {
|
||||
UserAPI.add(formData).then(() => {
|
||||
message.show("添加成功");
|
||||
hancleCloseDialog();
|
||||
handleQuery();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
function resetForm() {
|
||||
userFormRef.value.reset();
|
||||
Object.assign(formData, initialFormData);
|
||||
}
|
||||
|
||||
// 关闭弹窗
|
||||
function hancleCloseDialog() {
|
||||
dialog.visible = false;
|
||||
resetForm();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*
|
||||
* @param id 用户id
|
||||
*/
|
||||
function handleDelete(id: number) {
|
||||
message
|
||||
.confirm({
|
||||
msg: "确认删除用户吗?",
|
||||
title: "提示",
|
||||
})
|
||||
.then(() => {
|
||||
UserAPI.deleteByIds(id + "").then(() => {
|
||||
message.show("删除成功");
|
||||
handleQuery();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回
|
||||
*/
|
||||
function handleNavigateback() {
|
||||
uni.navigateBack();
|
||||
}
|
||||
|
||||
// 触底事件
|
||||
onReachBottom(() => {
|
||||
if (queryParams.pageNum * queryParams.pageSize < total.value) {
|
||||
loadmore();
|
||||
} else if (queryParams.pageNum * queryParams.pageSize >= total.value) {
|
||||
loadMoreState.value = "finished";
|
||||
}
|
||||
});
|
||||
|
||||
onLoad(() => {
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
// https://wot-design-uni.pages.dev/guide/common-problems#%E5%B0%8F%E7%A8%8B%E5%BA%8F%E6%A0%B7%E5%BC%8F%E9%9A%94%E7%A6%BB
|
||||
export default {
|
||||
options: {
|
||||
styleIsolation: "shared",
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.user-container {
|
||||
:deep(.wd-cell__wrapper) {
|
||||
padding: 4rpx 0;
|
||||
}
|
||||
|
||||
:deep(.wd-cell) {
|
||||
padding-right: 10rpx;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
:deep(.wd-fab__trigger) {
|
||||
width: 80rpx !important;
|
||||
height: 80rpx !important;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
padding: 10rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.data-container {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user