refactor: ♻️ 重构字典组件
重构字典组件
This commit is contained in:
@@ -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": {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
187
src/pages/mine/feedback/index.vue
Normal file
187
src/pages/mine/feedback/index.vue
Normal 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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user