refactor: ♻️ 重构字典组件

重构字典组件
This commit is contained in:
Theo
2024-12-03 14:36:13 +08:00
parent 605548fc37
commit b48499ec58
11 changed files with 335 additions and 121 deletions

View File

@@ -3,7 +3,7 @@
"autoscan": true,
"custom": {
"^wd-(.*)": "wot-design-uni/components/wd-$1/wd-$1.vue",
"^dict-(.*)": "@/components/dict/$1.vue"
"^cu-(.*)": "@/components/cu-$1/index.vue"
}
},
@@ -32,6 +32,12 @@
"navigationBarTitleText": "关于我们"
}
},
{
"path": "pages/mine/feedback/index",
"style": {
"navigationBarTitleText": "问题反馈"
}
},
{
"path": "pages/mine/settings/index",
"style": {

View File

@@ -77,7 +77,19 @@
</template>
<view class="charts-box">
<qiun-data-charts type="line" :chartData="chartData" />
<qiun-data-charts
type="line"
:chartData="chartData"
:opts="{
xAxis: {
rotateLabel: true, // 启用标签旋转
rotateAngle: -45, // 设置旋转角度
},
yAxis: {
disabled: true,
},
}"
/>
</view>
</wd-card>
</view>
@@ -194,7 +206,7 @@ const loadVisitStatsData = async () => {
const loadVisitTrendData = () => {
const endDate = new Date();
const startDate = new Date(endDate);
startDate.setDate(endDate.getDate() - recentDaysRange.value);
startDate.setDate(endDate.getDate() - recentDaysRange.value + 1);
const visitTrendQuery = {
startDate: dayjs(startDate).format("YYYY-MM-DD"),
@@ -234,7 +246,7 @@ onReady(() => {
<style setup lang="scss">
.home {
padding: 0 10rpx;
padding: 10rpx 10rpx;
:deep(.custom-item) {
height: 80px !important;
}

View File

@@ -0,0 +1,187 @@
<template>
<view class="feedback-container">
<!-- 问题类型选择 -->
<wd-cell-group title="问题类型" border>
<view class="radio-group">
<label v-for="item in feedbackTypes" :key="item.value" class="radio-item">
<text class="radio-text">{{ item.label }}</text>
<radio
:value="item.value"
:checked="feedbackType === item.value"
color="#0083ff"
class="radio-button"
style="transform: scale(0.8)"
@click="handleRadioChange(item.value)"
/>
</label>
</view>
</wd-cell-group>
<!-- 问题描述 -->
<wd-cell-group title="问题描述" border>
<wd-textarea
v-model="description"
placeholder="请详细描述您遇到的问题或建议..."
:maxlength="500"
show-count
:rows="5"
/>
</wd-cell-group>
<!-- 图片上传 -->
<wd-cell-group title="相关截图(选填)" border>
<view class="upload-box">
<wd-upload
v-model="fileList"
:max-count="3"
:before-read="beforeRead"
@delete="handleDelete"
/>
</view>
</wd-cell-group>
<!-- 联系方式 -->
<wd-cell-group title="联系方式(选填)" border>
<wd-input v-model="contact" placeholder="请输入您的手机号或邮箱" clearable />
</wd-cell-group>
<!-- 提交按钮 -->
<view class="submit-btn">
<wd-button type="primary" block :loading="submitting" @click="handleSubmit">
提交反馈
</wd-button>
</view>
<wd-toast />
</view>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { useToast } from "wot-design-uni";
const toast = useToast();
// 问题类型选项
const feedbackTypes = [
{ label: "功能异常", value: "bug" },
{ label: "优化建议", value: "suggestion" },
{ label: "其他问题", value: "other" },
];
// 表单数据
const feedbackType = ref("bug");
const description = ref("");
const fileList = ref<any[]>([]);
const contact = ref("");
const submitting = ref(false);
// 图片上传前的校验
const beforeRead = (file: any) => {
// 验证文件类型
const validTypes = ["image/jpeg", "image/png", "image/gif"];
if (!validTypes.includes(file.type)) {
toast.error("请上传 jpg、png 或 gif 格式的图片");
return false;
}
// 验证文件大小(限制为 5MB
if (file.size > 5 * 1024 * 1024) {
toast.error("图片大小不能超过 5MB");
return false;
}
return true;
};
// 删除图片
const handleDelete = (detail: any) => {
const index = detail.index;
fileList.value.splice(index, 1);
};
// 处理单选框变化
const handleRadioChange = (value: string) => {
feedbackType.value = value;
};
// 提交反馈
const handleSubmit = async () => {
// 表单验证
if (!description.value.trim()) {
toast.error("请描述您遇到的问题");
return;
}
submitting.value = true;
try {
// TODO: 调用提交反馈的接口
await new Promise((resolve) => setTimeout(resolve, 1500)); // 模拟提交
toast.success("提交成功");
// 重置表单
description.value = "";
fileList.value = [];
contact.value = "";
// 延迟返回上一页
setTimeout(() => {
uni.navigateBack();
}, 1500);
} catch (error) {
toast.error("提交失败,请重试");
} finally {
submitting.value = false;
}
};
</script>
<style lang="scss" scoped>
.feedback-container {
min-height: 100vh;
padding: 20rpx 0;
background-color: #f5f5f5;
:deep(.wd-cell-group__title) {
padding: 20rpx 30rpx 10rpx;
font-size: 28rpx;
color: #666;
}
.radio-group {
padding: 4rpx 0;
background-color: #fff;
}
.radio-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10rpx 30rpx;
border-bottom: 1px solid #eee;
&:last-child {
border-bottom: none;
}
}
.radio-text {
font-size: 22rpx;
color: #333;
}
.upload-box {
padding: 20rpx 30rpx;
}
.submit-btn {
margin: 40rpx 30rpx;
}
:deep(.wd-textarea) {
padding: 20rpx 30rpx;
background-color: #fff;
}
.radio-button {
margin-right: -8rpx;
}
}
</style>

View File

@@ -27,7 +27,7 @@
</view>
<!-- 编辑资料 -->
<view v-if="isLogin" class="cursor-pointer">
<wd-icon name="setting" />
<wd-icon name="setting" @click="navigateToProfile" />
</view>
</view>
<!-- 功能操作 -->
@@ -46,7 +46,7 @@
<wd-cell title="常见问题" icon="help-circle" @click="navigateToFAQ">
<wd-icon name="arrow-right" />
</wd-cell>
<wd-cell title="问题反馈" icon="check-circle" clickable @click="navigateToAbout">
<wd-cell title="问题反馈" icon="check-circle" clickable @click="handleQuestionFeedback">
<wd-icon name="arrow-right" />
</wd-cell>
<wd-cell title="设置" icon="setting1" clickable @click="navigateToSettings">
@@ -86,11 +86,15 @@ const navigateToFAQ = () => {
const navigateToAbout = () => {
uni.navigateTo({ url: "/pages/mine/about/index" });
};
// 应用设置
// 设置
const navigateToSettings = () => {
uni.navigateTo({ url: "/pages/mine/settings/index" });
};
// 问题反馈
const handleQuestionFeedback = () => {
uni.navigateTo({ url: "/pages/mine/feedback/index" });
};
// 建设中
const handleItemclick = (item: any) => {
toast.show("建设中...");
};
@@ -117,6 +121,13 @@ const handleItemclick = (item: any) => {
color: #4d80f0;
border-radius: 10rpx;
}
.cursor-pointer {
display: flex;
align-items: center;
justify-content: center;
margin: auto;
margin-right: 10rpx;
}
}
}

View File

@@ -21,7 +21,7 @@
</wd-drop-menu-item>
</wd-drop-menu>
<view class="mt-20rpx">
<view class="data-container">
<!-- 列表内容 -->
<view v-for="(item, index) in pageData" :key="index" class="mb-20rpx">
<wd-card>
@@ -31,32 +31,11 @@
</view>
</template>
<wd-row class="mb-20rpx">
<wd-col :span="24">
<wd-col :span="5">
<view>配置键</view>
</wd-col>
<wd-col :span="19">
<view>{{ item.configKey || "-" }}</view>
</wd-col>
</wd-col>
<wd-col :span="24">
<wd-col :span="5">
<view>配置值</view>
</wd-col>
<wd-col :span="19">
<view>{{ item.configValue || "-" }}</view>
</wd-col>
</wd-col>
<wd-col :span="24">
<wd-col :span="5">
<view>备注</view>
</wd-col>
<wd-col :span="19">
<view>{{ item.remark || "-" }}</view>
</wd-col>
</wd-col>
</wd-row>
<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)">
@@ -194,6 +173,8 @@ async function submitForm() {
} catch (error) {
uni.showToast({ title: "操作失败", icon: "error" });
loading.value = false;
} finally {
loading.value = false;
}
}
@@ -239,11 +220,11 @@ function loadmore() {
* 添加
*/
function handleOpenDialog() {
form.id = undefined;
form.configName = "";
form.configKey = "";
form.configValue = "";
form.remark = "";
form.value.id = undefined;
form.value.configName = "";
form.value.configKey = "";
form.value.configValue = "";
form.value.remark = "";
showEditPopup.value = true;
}
@@ -311,3 +292,33 @@ onLoad(() => {
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>

View File

@@ -75,7 +75,6 @@ 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";
import CuDateQuery from "@/components/cu-date-query/index.vue";
const filterDropMenu = ref<DropMenuItemExpose>();
const loadMoreState = ref<LoadMoreState>("loading");

View File

@@ -9,7 +9,7 @@
<div class="notice-meta">
<div class="meta-row">
优先级
<dict-label code="notice_level" :model-value="noticeDetail.level" />
<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>
@@ -22,28 +22,10 @@
</template>
<script setup lang="ts">
import type { NoticeDetailVO } from "@/api/system/notice";
import NoticeAPI from "@/api/system/notice";
import NoticeAPI, { NoticeDetailVO } from "@/api/system/notice";
const noticeDetail = ref<NoticeDetailVO>({});
const getLevelText = (level?: string) => {
const textMap: Record<string, string> = {
L: "低",
M: "中",
H: "高",
};
return textMap[level || "L"];
};
const getLevelType = (level?: string): "primary" | "warning" | "danger" => {
const typeMap: Record<string, "primary" | "warning" | "danger"> = {
L: "primary",
M: "warning",
H: "danger",
};
return typeMap[level || "L"];
};
/**
* 获取通知详情
* @param id 通知ID
@@ -51,13 +33,13 @@ const getLevelType = (level?: string): "primary" | "warning" | "danger" => {
const getNoticeDetail = async (id: string) => {
try {
const res = await NoticeAPI.getDetail(id);
console.log(res);
noticeDetail.value = res;
} catch (error) {
console.error("获取通知详情失败:", error);
}
};
// 页面加载
onLoad((options: any) => {
if (options && options.id) {
getNoticeDetail(options.id as string);

View File

@@ -22,63 +22,46 @@
</wd-drop-menu>
<!-- 列表内容 -->
<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-row class="mb-20rpx">
<wd-col :span="24">
<wd-col :span="8">
<view>通告目标类型</view>
</wd-col>
<wd-col :span="16">
<view>{{ item.targetType === 1 ? "指定" : "全体" }}</view>
</wd-col>
</wd-col>
<wd-col :span="24">
<wd-col :span="8">
<view>发布人</view>
</wd-col>
<wd-col :span="16">
<view>{{ item.publisherName || "-" }}</view>
</wd-col>
</wd-col>
<wd-col v-if="item.publishStatus === 1" :span="24">
<wd-col :span="8">
<view>发布时间</view>
</wd-col>
<wd-col :span="16">
<view>{{ formatDate(item.publishTime) }}</view>
</wd-col>
</wd-col>
<wd-col v-else :span="24">
<wd-col :span="8">
<view>撤回时间</view>
</wd-col>
<wd-col :span="16">
<view>{{ formatDate(item.revokeTime) }}</view>
</wd-col>
</wd-col>
<wd-col :span="24">
<wd-col :span="8">
<view>紧急程度</view>
</wd-col>
<wd-col :span="16">
<dict-label code="notice_level" :model-value="item.level" />
</wd-col>
</wd-col>
</wd-row>
<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>
<template #footer>
<wd-button size="small" plain type="primary" @click="handleAction(item)">操作</wd-button>
</template>
</wd-card>
<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>
<!-- 加载更多 -->
@@ -288,3 +271,29 @@ 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>

View File

@@ -162,9 +162,6 @@ import UserAPI, { type UserPageQuery, UserPageVO, UserForm } from "@/api/system/
import RoleAPI from "@/api/system/role";
import DeptAPI from "@/api/system/dept";
import CuPicker from "@/components/cu-picker/index.vue";
import CuDateQuery from "@/components/cu-date-query/index.vue";
const message = useMessage();
const loadMoreState = ref<LoadMoreState>("loading");
const filterDropMenu = ref();