diff --git a/api/index/index.js b/api/index/index.js
new file mode 100644
index 0000000..f439c62
--- /dev/null
+++ b/api/index/index.js
@@ -0,0 +1,23 @@
+
+import { post, get } from '@/common/utils/request';
+
+
+/**
+ * 任务完成情况统计
+ * @param {Object} params {mobile, password, code}
+ * @returns {Promise}
+ */
+export const getTaskCompletionSummary = (params) => {
+ return post('/app-api/homePage/summary/taskCompletionSummary', params);
+};
+
+
+/**
+ * 任务待办已办
+ * @param {Object} params {mobile, password, code}
+ * @returns {Promise}
+ */
+export const getTaskDetails = (params) => {
+ return post('/app-api/homePage/summary/taskDetails', params);
+};
+
diff --git a/components/uni-charts/uni-charts.vue b/components/uni-charts/uni-charts.vue
index 5c9693b..573313c 100644
--- a/components/uni-charts/uni-charts.vue
+++ b/components/uni-charts/uni-charts.vue
@@ -88,7 +88,7 @@ export default {
this.drawLine()
}
},
- // 折线图绘制(终极版:Y轴整数 + 自适应极值 + 修复文字折叠 + 优化图例间距)
+ // 折线图绘制(移除平滑过渡,改为纯直线)
drawLine () {
if (!this.data.length || !this.categories.length) return;
@@ -100,8 +100,7 @@ export default {
xAxis = {},
yAxis = {},
legend = {},
- color = ['#25AF69', '#B34C17'],
- lineSmooth = true
+ color = ['#25AF69', '#B34C17']
} = this.option
// 清空画布
@@ -154,7 +153,7 @@ export default {
ctx.lineTo(width - gridRight, y)
ctx.stroke()
- // ========== 核心修改:Y轴显示整数(无小数点) ==========
+ // Y轴显示整数(无小数点)
ctx.setFillStyle(yAxis.axisLabel?.color || '#666')
ctx.setFontSize(yAxis.axisLabel?.fontSize || 12)
const val = minVal + (i * yTickStep)
@@ -211,7 +210,7 @@ export default {
})
}
- // 绘制平滑折线(无数据点)
+ // ========== 核心修改:移除平滑曲线,改为纯直线连接 ==========
this.data.forEach((series, seriesIdx) => {
const seriesColor = series.color || color[seriesIdx % color.length]
@@ -226,21 +225,8 @@ export default {
if (index === 0) {
ctx.moveTo(x, y)
} else {
- if (lineSmooth && index < series.data.length - 1) {
- const prevX = gridLeft + (index - 1) * xStep
- const prevY = gridTop + drawHeight - ((series.data[index - 1] - minVal) / valRange) * drawHeight
- const nextX = gridLeft + (index + 1) * xStep
- const nextY = gridTop + drawHeight - ((series.data[index + 1] - minVal) / valRange) * drawHeight
-
- const cp1x = (prevX + x) / 2
- const cp1y = prevY
- const cp2x = (x + nextX) / 2
- const cp2y = y
-
- ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
- } else {
- ctx.lineTo(x, y)
- }
+ // 直接直线连接,移除所有贝塞尔曲线平滑逻辑
+ ctx.lineTo(x, y)
}
})
@@ -249,7 +235,7 @@ export default {
ctx.draw()
},
- // K线图绘制(同步修改Y轴为整数)
+ // K线图绘制(同步修改Y轴为整数,K线本身无平滑逻辑,保持原样)
drawKline () {
const ctx = uni.createCanvasContext('uni-charts', this)
this.ctx = ctx
@@ -322,7 +308,7 @@ export default {
}
})
- // 绘制K线
+ // 绘制K线(K线本身就是直线,无平滑逻辑)
this.data.forEach((item, index) => {
const { open, high, low, close } = item
const x = gridLeft + index * xStep + xStep / 2
@@ -331,7 +317,7 @@ export default {
const yHigh = gridTop + drawHeight - ((high - minVal) / valRange) * drawHeight
const yLow = gridTop + drawHeight - ((low - minVal) / valRange) * drawHeight
- // 绘制高低线
+ // 绘制高低线(直线)
ctx.setStrokeStyle(close >= open ? color[0] : color[1])
ctx.setLineWidth(1)
ctx.beginPath()
diff --git a/pages-sub/daily/maintain-manage/finish-plan-detail.vue b/pages-sub/daily/maintain-manage/finish-plan-detail.vue
index f72c6ee..32183d4 100644
--- a/pages-sub/daily/maintain-manage/finish-plan-detail.vue
+++ b/pages-sub/daily/maintain-manage/finish-plan-detail.vue
@@ -9,22 +9,15 @@
>
-
-
-
+
+
-
-
+
- {{i.planName || '--'}}
+ {{i.planName || '--'}}
-
-
-
@@ -44,34 +37,42 @@
-
+
-
+
+
+
+
+
+
暂无问题照片
-
+
- 巡查描述
+ 巡查描述
- {{i.remark || '--'}}
+ {{i.remark || '--'}}
@@ -81,7 +82,6 @@
align="middle"
>
-
-
+
@@ -99,10 +99,44 @@ import {ref} from 'vue';
import {detailList} from "@/api/maintain-manage/maintain-manage";
import {onLoad} from '@dcloudio/uni-app';
import {timeFormat} from '@/uni_modules/uview-plus';
+
// 状态管理
const loading = ref(true);
const orderDetail = ref([]);
+/**
+ * 格式化图片URL(兼容WebP + 清理非法字符)
+ * @param urls 原始图片列表
+ */
+const formatImageUrls = (urls) => {
+ if (!Array.isArray(urls) || urls.length === 0) return [];
+
+ return urls.map(url => {
+ if (typeof url !== 'string') return '';
+ // 1. 清理URL开头的非法字符(如数字、空格)
+ const validStart = url.indexOf('http');
+ const cleanUrl = validStart > 0 ? url.substring(validStart) : url;
+ // 2. 小程序兼容:WebP转JPEG(可选,后端无转换则注释)
+ // return cleanUrl.replace('.webp', '.jpeg');
+ return cleanUrl;
+ }).filter(url => !!url);
+};
+
+/**
+ * 预览图片
+ * @param currentUrl 当前点击的图片
+ * @param allUrls 所有图片列表
+ */
+const previewImage = (currentUrl, allUrls) => {
+ uni.previewImage({
+ current: currentUrl,
+ urls: allUrls,
+ fail: (err) => {
+ console.error('预览图片失败:', err);
+ uni.showToast({title: '预览图片失败', icon: 'none'});
+ }
+ });
+};
/**
* 获取工单详情
@@ -111,14 +145,18 @@ const getOrderDetail = async (planNo: string) => {
try {
loading.value = true;
let queryData = {
- planNo:planNo,
- pageSize:100,
- pageNo:1,
- }
+ planNo: planNo,
+ pageSize: 100,
+ pageNo: 1,
+ };
const res = await detailList(queryData);
console.log('接口返回:', res);
- orderDetail.value = res.list;
+ // 修复2:正确解析接口数据(res.data.list 而非 res.list)
+ orderDetail.value = res.data?.list || res.list || [];
+
+ // 调试:打印格式化后的图片URL
+ console.log('格式化后图片URL:', formatImageUrls(orderDetail.value[0]?.beginImgList || []));
} catch (error) {
console.error('获取工单详情失败:', error);
uni.showToast({title: '加载失败,请重试', icon: 'none'});
@@ -140,7 +178,6 @@ onLoad((options) => {
\ No newline at end of file
diff --git a/pages-sub/data/tree-archive/addTree.vue b/pages-sub/data/tree-archive/addTree.vue
index f280f9e..98f844a 100644
--- a/pages-sub/data/tree-archive/addTree.vue
+++ b/pages-sub/data/tree-archive/addTree.vue
@@ -453,7 +453,7 @@ const submit = async () => {
\ No newline at end of file
diff --git a/pages/index/index.vue b/pages/index/index.vue
index f9e3a27..fa841ef 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -1,5 +1,5 @@
-
+
@@ -9,7 +9,7 @@
-
+
@@ -24,13 +24,14 @@
-
-
-
- 待办事项({{ todoList.length }})
-
-
-
- 已办事项({{ doneList.length }})
-
-
-
-
-
-
-
-
-
- {{ item.name }}
-
-
-
- {{ item.urgency || '普通' }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.taskName || '无' }}
+
+
- {{ timeFormat(item.time) }}
-
+
-
@@ -267,21 +357,22 @@ $text-color-light: #666;
$text-color-placeholder: #999;
$bg-color: #f5f5f7;
$card-bg: #fff;
-$border-radius: 32rpx;
-$card-radius: 10rpx;
-$spacing-sm: 10rpx;
-$spacing-md: 20rpx;
-$spacing-lg: 30rpx;
-
-.home-page {
- background-color: $bg-color;
+$border-radius: 16px;
+$card-radius: 5px;
+$spacing-sm: 5px;
+$spacing-md: 10px;
+$spacing-lg: 15px;
+$border-color: #e5e5e5; // 新增边框颜色变量
+
+.page-container {
min-height: 100vh;
+ background-color: $bg-color;
}
.user-info-bar {
background: url("https://img.jichengshanshui.com.cn:28207/appimg/bg.jpg") no-repeat;
background-size: 100% 100%;
- padding: 200rpx $spacing-lg 270rpx;
+ padding: 100px $spacing-lg 135px;
display: flex;
justify-content: space-between;
align-items: center;
@@ -292,16 +383,16 @@ $spacing-lg: 30rpx;
.username {
font-size: 16px;
font-weight: 500;
- margin-bottom: 8rpx;
+ margin-bottom: 4px;
}
.login-desc {
- font-size: 16px;
+ font-size: 16px;
}
.msg-icon {
position: relative;
- padding: 10rpx;
+ padding: 5px;
border-radius: 50%;
transition: background-color 0.2s;
@@ -311,27 +402,27 @@ $spacing-lg: 30rpx;
.msg-badge {
position: absolute;
- top: -10rpx;
- right: -10rpx;
+ top: -5px;
+ right: -5px;
}
}
}
.content-wrap {
- margin-top: -245rpx;
+ margin-top: -122px;
border-radius: $border-radius $border-radius 0 0;
background-color: $bg-color;
position: relative;
z-index: 2;
overflow: hidden;
+ padding-bottom: $spacing-lg;
}
.module-title {
- padding: $spacing-lg $spacing-lg 0;
- font-size: 30rpx;
+ padding: $spacing-lg;
+ font-size: 15px;
font-weight: 600;
color: $text-color-light;
- margin-bottom: $spacing-sm;
}
.task-chart-card {
@@ -344,13 +435,13 @@ $spacing-lg: 30rpx;
display: flex;
justify-content: space-between;
align-items: center;
- font-size: 24rpx;
+ font-size: 12px;
color: $text-color-placeholder;
margin-bottom: $spacing-md;
.date-picker-wrap {
- padding: 4rpx 8rpx;
- border-radius: 6rpx;
+ padding: 2px 4px;
+ border-radius: 3px;
transition: background-color 0.2s;
&:active {
@@ -361,105 +452,58 @@ $spacing-lg: 30rpx;
.chart-container {
width: 100%;
- height: 300rpx;
+ height: 150px;
display: flex;
align-items: center;
justify-content: center;
}
}
-.tab-switch-bar {
- display: flex;
- margin: 0 $spacing-lg;
- background-color: $card-bg;
- border-radius: $card-radius $card-radius 0 0;
-
- .tab-item {
- flex: 1;
- text-align: center;
- padding: $spacing-md 0;
- font-size: 28rpx;
- color: $text-color-light;
- position: relative;
- transition: color 0.2s;
-
- &--hover {
- background-color: $bg-color;
- }
-
- &.active {
- color: $primary-color;
- font-weight: 500;
- }
-
- .tab-active-line {
- position: absolute;
- bottom: 0;
- left: 0;
- width: 100%;
- height: 4rpx;
- background-color: $primary-color;
- }
- }
+.task-tab-container {
+ position: relative;
+ z-index: 4;
+ margin: 0 $spacing-lg $spacing-sm;
}
.task-list-container {
- background-color: $card-bg;
margin: 0 $spacing-lg;
- padding: $spacing-md;
- border-radius: 0 0 $card-radius $card-radius;
- box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
-
- .task-item {
- padding: $spacing-md;
- border-bottom: 1px solid $bg-color;
- transition: background-color 0.2s;
-
- &--hover {
- background-color: $bg-color;
- }
-
- &:last-child {
- border-bottom: none;
- }
+ background-color: $card-bg;
+ border-radius: $card-radius;
+ overflow: hidden; // 防止边框溢出圆角
+}
- .task-name {
- font-size: 28rpx;
- color: $text-color;
- margin-bottom: $spacing-sm;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
+.task-item {
+ padding: $spacing-md;
+ transition: background-color 0.2s;
+ border-bottom: 1px solid $border-color;
+ &:last-child {
+ border-bottom: none;
+ }
- .task-meta {
- display: flex;
- justify-content: space-between;
- align-items: center;
- font-size: 24rpx;
+ &--hover {
+ background-color: $bg-color;
+ }
- .urgency-tag {
- padding: 2rpx 8rpx;
- border-radius: 4rpx;
- color: #fff;
+ &__content {
+ width: 100%;
+ }
- &--urgent {
- background-color: $danger-color;
- }
+ &__name {
+ font-size: 13px;
+ color: $text-color;
+ margin-bottom: $spacing-sm;
+ }
- &--high {
- background-color: #fa8c16;
- }
+ &__footer {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ }
+}
- &--normal {
- background-color: $text-color-placeholder;
- }
- }
+// 紧急程度标签样式
+.urgency-tag {
+ color: #7D7D7D;
- .task-time {
- color: $text-color-placeholder;
- }
- }
- }
}
\ No newline at end of file
diff --git a/pages/login/index.vue b/pages/login/index.vue
index a9d1623..173b1b9 100644
--- a/pages/login/index.vue
+++ b/pages/login/index.vue
@@ -1,27 +1,49 @@
-
+
你好,欢迎光临
全域智能运营管理平台
-
+
-
- 账户登录
+
+
-
+
-
-
+
+
+ loginFormRef.validateField('mobile')"
+ />
+
+
+
+
loginFormRef.validateField('account')"
/>
-
+
loginFormRef.validateField('password')"
/>
+
+
+
+
+
+
@@ -82,92 +113,165 @@ import { ref, reactive, onMounted, nextTick } from 'vue';
import { useUserStore } from '@/pinia/user';
import globalConfig from '@/common/config/global';
-// ========== 【全局实例 & 基础状态】 和工单页写法一致 ==========
+// 全局实例 & 基础状态
const userStore = useUserStore();
-const loginFormRef = ref(null); // 表单ref 用于校验
-const isLoading = ref(false); // 登录加载状态
+const loginFormRef = ref(null);
+const isLoading = ref(false);
+
+// Tabs配置(name直接存储显示文本)
+const tabList = ref([
+ { name: '手机号登录' },
+ { name: '账号登录' }
+]);
+const loginType = ref('手机号登录'); // 登录类型标识
+
+// 记住密码(默认选中)
+const rememberPwd = ref(true);
-// ========== 【表单数据】 和工单页一致的 reactive 声明 ==========
+// 表单数据
const form = reactive({
- account: '', // 账号
- password: '' // 密码
+ account: '', // 账号
+ mobile: '', // 手机号
+ password: '' // 密码
});
-// ========== 【表单校验规则】 ✅核心 和工单页1:1同款校验规则写法 ==========
+// 表单校验规则
const loginFormRules = reactive({
- // 账号校验:必填 + 长度限制 2-30位(合理账号长度,可自行调整)
account: [
{ type: 'string', required: true, message: '请输入登录账号', trigger: ['change', 'blur'] },
{ type: 'string', min: 2, max: 30, message: '账号长度为2-30个字符', trigger: ['change', 'blur'] }
],
- // 密码校验:必填 + 长度限制 6-20位(行业通用密码长度,可自行调整)
+ mobile: [
+ { type: 'string', required: true, message: '请输入手机号', trigger: ['change', 'blur'] },
+ { type: 'string', pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式', trigger: ['change', 'blur'] }
+ ],
password: [
{ type: 'string', required: true, message: '请输入登录密码', trigger: ['change', 'blur'] },
{ type: 'string', min: 3, max: 20, message: '密码长度为3-20个字符', trigger: ['change', 'blur'] }
]
});
-// ========== 【生命周期】 nextTick 设置校验规则 和工单页一致 ==========
+// Tabs切换事件
+const handleTabChange = ({name}) => {
+ console.log(name)
+ if (isLoading.value) return;
+ loginType.value = name;
+
+ // 切换时清空另一类输入框
+ if (name === '手机号登录') {
+ form.account = '';
+ } else {
+ form.mobile = '';
+ }
+
+ // 清空校验状态
+ nextTick(() => {
+ loginFormRef.value?.clearValidate();
+ });
+};
+
+// 生命周期
onMounted(() => {
// 检查登录态
checkLoginStatus();
- // nextTick确保表单挂载完成再赋值规则,修复校验不生效bug,和工单页写法一致
+
+ // 初始化表单校验规则
nextTick(() => {
loginFormRef.value?.setRules(loginFormRules);
});
+
+ // 读取缓存的账号/密码
+ if (rememberPwd.value) {
+ try {
+ const savedAccount = uni.getStorageSync('login_account') || '';
+ const savedMobile = uni.getStorageSync('login_mobile') || '';
+ const savedPwd = uni.getStorageSync('login_password') || '';
+
+ if (savedAccount) {
+ form.account = savedAccount;
+ loginType.value = '账号登录';
+
+ } else if (savedMobile) {
+ form.mobile = savedMobile;
+ loginType.value = '手机号登录';
+ }
+ form.password = savedPwd;
+ } catch (err) {
+ console.warn('读取缓存密码失败:', err);
+ }
+ }
});
-// ========== 【检查登录状态】 原有逻辑不变 ==========
+// 检查登录状态
const checkLoginStatus = () => {
try {
- // 已登录则直接跳首页
if (userStore.isLogin) {
uni.switchTab({
url: '/pages/workbench/index',
- fail: () => {
- uni.reLaunch({ url: '/pages/workbench/index' });
- }
+ fail: () => uni.reLaunch({ url: '/pages/workbench/index' })
});
- return;
}
} catch (err) {
console.warn('检查登录状态失败:', err);
}
};
-// ========== 【核心登录方法】 ✅ 完整表单校验 + 登录逻辑,和工单页submit提交逻辑一致 ==========
+// 登录方法
const handleLogin = async () => {
try {
- // ✅ 第一步:先执行表单整体校验,通过后再执行登录逻辑(和工单页submitWorkOrder写法一致)
+ // 表单校验
await loginFormRef.value.validate();
-
isLoading.value = true;
- // 执行登录请求
- await userStore.login({
- username: form.account,
- password: form.password
- });
- uni.showToast({ title: '登录成功', icon: 'success', duration: 1000 });
+ // 组装登录参数
+ const loginParams = { password: form.password };
+ if (loginType.value === '手机号登录') {
+ // loginParams.mobile = form.mobile;
+ loginParams.username = form.mobile;
+ } else {
+ loginParams.username = form.account;
+ }
+
+ // 执行登录
+ await userStore.login(loginParams);
- // 登录成功后跳转首页
+ // 保存记住密码
+ if (rememberPwd.value) {
+ try {
+ if (loginType.value === '手机号登录') {
+ uni.setStorageSync('login_mobile', form.mobile);
+ uni.removeStorageSync('login_account');
+ } else {
+ uni.setStorageSync('login_account', form.account);
+ uni.removeStorageSync('login_mobile');
+ }
+ uni.setStorageSync('login_password', form.password);
+ } catch (err) {
+ console.warn('保存密码失败:', err);
+ }
+ } else {
+ // 清除缓存
+ uni.removeStorageSync('login_account');
+ uni.removeStorageSync('login_mobile');
+ uni.removeStorageSync('login_password');
+ }
+
+ // 登录成功提示+跳转
+ uni.showToast({ title: '登录成功', icon: 'success', duration: 1000 });
setTimeout(() => {
uni.switchTab({
url: globalConfig.router.tabBarList[1].path,
- fail: (err) => {
- console.warn('tabBar跳转失败,切换为普通跳转:', err);
- uni.reLaunch({ url: '/pages/workbench/index' });
- }
+ fail: () => uni.reLaunch({ url: '/pages/workbench/index' })
});
}, 1000);
} catch (err) {
- // ✅ 校验失败/登录失败 统一捕获提示,和工单页异常处理一致
+ // 错误处理
if (!Array.isArray(err)) {
console.error('登录失败:', err);
uni.showToast({
- title: err.message || '账号或密码错误,请重试',
+ title: err.msg || '账号或密码错误,请重试',
icon: 'none',
- duration: 2000
+ duration: 1000
});
}
} finally {
@@ -187,18 +291,16 @@ const handleLogin = async () => {
background: #f5f7fa;
}
-// 顶部:从左到右 由浅到深 线性渐变 过渡自然柔和 无突兀色块
+// 顶部样式
.top-title {
- //background: linear-gradient(120deg, #4299e1 0%, #2970e8 50%, #2563eb 100%);
+ background: url("https://img.jichengshanshui.com.cn:28207/appimg/bg.jpg") no-repeat;
+ background-size: 100% 100%;
color: #fff;
- padding: 220rpx 30rpx 200rpx;
+ padding: 200rpx 0 200rpx 40rpx;
text-align: left;
- //border-bottom-left-radius: 120rpx;
position: relative;
z-index: 1;
- //box-shadow: 0 25rpx 40rpx -15rpx rgba(37, 99, 235, 0.3);
- background: url("https://img.jichengshanshui.com.cn:28207/appimg/bg.jpg") no-repeat;
- background-size: 100% 100%;
+
.welcome-text {
font-size: 23px;
display: block;
@@ -223,37 +325,64 @@ const handleLogin = async () => {
position: relative;
z-index: 10;
box-sizing: border-box;
+}
- .login-title {
- font-size: 19px;
- font-weight: 600;
- color: #666;
- margin-bottom: 15px;
- letter-spacing: 1px;
+// Tabs样式适配
+:deep(.u-tabs) {
+ margin-bottom: 15px;
+ .u-tabs__content {
+ height: auto !important;
+ }
+ .u-tab-item {
+ padding: 0 10px;
}
}
-// 适配表单校验的间距
+// 表单间距
:deep(.u-form-item) {
margin-bottom: 10px;
position: relative;
}
+// 密码项样式
+.password-item {
+ position: relative;
+ margin-bottom: 5px !important;
+}
+
+// ✅ 核心优化:记住密码完全居右对齐
+.remember-wrap {
+ //text-align: right;
+ padding: 0; // 移除多余内边距
+ margin: 10px 0 20px;
+
+ :deep(.u-checkbox) {
+ font-size: 12px;
+ color: #666;
+ justify-content: flex-end;
+ // 移除复选框的默认左边距,确保居右紧凑
+ margin-left: 0 !important;
+
+ .u-checkbox__label {
+ margin-left: 5px;
+ }
+ }
+}
+
// 登录按钮
.login-btn {
- margin-top: 20px;
+ margin-top: 10px;
width: 100%;
height: 44px;
line-height: 44px;
border-radius: 4px;
font-size: 16px;
-
background: #0A86F4;
box-shadow: 0px 4px 6px 1px rgba(25,94,215,0.5);
border-radius: 23px;
}
-
+// 版权信息
.copyright {
width: 100%;
text-align: center;
diff --git a/pages/mine/index.vue b/pages/mine/index.vue
index 3ce566d..2689cd1 100644
--- a/pages/mine/index.vue
+++ b/pages/mine/index.vue
@@ -1,5 +1,5 @@
-
+