Commit 24c0bbe72df0d1e9611993ade850bf97b0e1f495

Authored by 刘淇
1 parent 53012a16

登录账号密码 加密存储

package-lock.json
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 "": { 6 "": {
7 "dependencies": { 7 "dependencies": {
8 "clipboard": "^2.0.11", 8 "clipboard": "^2.0.11",
  9 + "crypto-js": "^4.2.0",
9 "dayjs": "^1.11.19", 10 "dayjs": "^1.11.19",
10 "pinia-plugin-persistedstate": "^4.7.1" 11 "pinia-plugin-persistedstate": "^4.7.1"
11 }, 12 },
@@ -85,6 +86,12 @@ @@ -85,6 +86,12 @@
85 "dev": true, 86 "dev": true,
86 "license": "MIT" 87 "license": "MIT"
87 }, 88 },
  89 + "node_modules/crypto-js": {
  90 + "version": "4.2.0",
  91 + "resolved": "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz",
  92 + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
  93 + "license": "MIT"
  94 + },
88 "node_modules/dayjs": { 95 "node_modules/dayjs": {
89 "version": "1.11.19", 96 "version": "1.11.19",
90 "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.19.tgz", 97 "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.19.tgz",
package.json
1 { 1 {
2 "dependencies": { 2 "dependencies": {
3 "clipboard": "^2.0.11", 3 "clipboard": "^2.0.11",
  4 + "crypto-js": "^4.2.0",
4 "dayjs": "^1.11.19", 5 "dayjs": "^1.11.19",
5 "pinia-plugin-persistedstate": "^4.7.1" 6 "pinia-plugin-persistedstate": "^4.7.1"
6 }, 7 },
pages-sub/daily/maintain-manage/road-detail-list.vue
@@ -54,7 +54,7 @@ @@ -54,7 +54,7 @@
54 <!-- 自定义标题区域 --> 54 <!-- 自定义标题区域 -->
55 <template #head> 55 <template #head>
56 <view class="card-header"> 56 <view class="card-header">
57 - <view class="common-card-title common-name">{{ item.planName || '无计划名称' }}{{ item.planName || '无计划名称' }}</view> 57 + <view class="common-card-title common-name">{{ item.planName || '无计划名称' }}</view>
58 <!-- 已失效标识 --> 58 <!-- 已失效标识 -->
59 <view v-show="item.finishState == 3 " class="common-invalid-tag">已失效</view> 59 <view v-show="item.finishState == 3 " class="common-invalid-tag">已失效</view>
60 <view v-show="item.finishState == 2 " class="common-finish-tag">已完成</view> 60 <view v-show="item.finishState == 2 " class="common-finish-tag">已完成</view>
pages-sub/data/tree-archive/addTree.vue
1 <template> 1 <template>
2 - <view class="container"> 2 + <view class="page-container">
3 <up-form :model="formData" ref="formRef" label-width="140rpx" border-bottom> 3 <up-form :model="formData" ref="formRef" label-width="140rpx" border-bottom>
4 <up-form-item label="名称" prop="treetype" required> 4 <up-form-item label="名称" prop="treetype" required>
5 <up-input v-model.trim="formData.treetype" placeholder="请输入名称" maxlength="30" border="none"/> 5 <up-input v-model.trim="formData.treetype" placeholder="请输入名称" maxlength="30" border="none"/>
@@ -452,7 +452,7 @@ const submit = async () =&gt; { @@ -452,7 +452,7 @@ const submit = async () =&gt; {
452 </script> 452 </script>
453 453
454 <style scoped lang="scss"> 454 <style scoped lang="scss">
455 -.container { 455 +.page-container {
456 padding: 15px; 456 padding: 15px;
457 box-sizing: border-box; 457 box-sizing: border-box;
458 background: #fff; 458 background: #fff;
pages-sub/data/tree-archive/logDetail.vue
1 <template> 1 <template>
2 - <view class="container"> 2 + <view class="page-container">
3 <up-form :model="formData" ref="formRef" label-width="140rpx" border-bottom> 3 <up-form :model="formData" ref="formRef" label-width="140rpx" border-bottom>
4 <up-form-item label="名称" prop="treetype" required> 4 <up-form-item label="名称" prop="treetype" required>
5 <up-input v-model="formData.treetype" placeholder="请输入名称" maxlength="30" border="none" readonly/> 5 <up-input v-model="formData.treetype" placeholder="请输入名称" maxlength="30" border="none" readonly/>
@@ -205,7 +205,7 @@ onReady(() =&gt; {}); @@ -205,7 +205,7 @@ onReady(() =&gt; {});
205 </script> 205 </script>
206 206
207 <style scoped lang="scss"> 207 <style scoped lang="scss">
208 -.container { 208 +.page-container {
209 padding: 25rpx; 209 padding: 25rpx;
210 box-sizing: border-box; 210 box-sizing: border-box;
211 background: #fff; 211 background: #fff;
pages-sub/data/tree-archive/treeRecord.vue
1 <template> 1 <template>
2 <view class="container"> 2 <view class="container">
  3 +
  4 + <!-- 内容区域 - 集成z-paging分页 -->
  5 + <z-paging
  6 + ref="pagingRef"
  7 + v-model="rows"
  8 + @query="fetchData"
  9 + :auto-show-system-loading="true"
  10 + >
  11 + <!-- 空数据提示 -->
  12 + <template #empty>
  13 + <empty-view/>
  14 + </template>
3 <!-- 空数据组件 --> 15 <!-- 空数据组件 -->
4 - <up-empty v-if="rows.length === 0" text="暂无数据" marginTop="100"></up-empty> 16 +<!-- <up-empty v-if="rows.length === 0" text="暂无数据" marginTop="100"></up-empty>-->
5 17
6 <!-- 树木列表:up-card重构 + 保留原始背景图写法 核心满足你的要求 --> 18 <!-- 树木列表:up-card重构 + 保留原始背景图写法 核心满足你的要求 -->
7 - <view class="record-wrap" v-else> 19 + <view class="record-wrap" >
8 <up-card 20 <up-card
9 v-for="i in rows" 21 v-for="i in rows"
10 - :key="i.id" 22 + :key="i.treenumber"
11 :border="false" 23 :border="false"
12 :show-head="false" 24 :show-head="false"
13 class="tree-card" 25 class="tree-card"
@@ -16,7 +28,6 @@ @@ -16,7 +28,6 @@
16 > 28 >
17 <template #body> 29 <template #body>
18 <view class="card-body-inner"> 30 <view class="card-body-inner">
19 - <!-- ✅ 保留你的 原生背景图写法 完全没动 核心要求满足 -->  
20 <view class="record-list-left" :style="`background-image: url(${i.treephoto});`"></view> 31 <view class="record-list-left" :style="`background-image: url(${i.treephoto});`"></view>
21 32
22 <view class="record-list-right"> 33 <view class="record-list-right">
@@ -36,15 +47,9 @@ @@ -36,15 +47,9 @@
36 树木编号:{{ i.treenumber }} 47 树木编号:{{ i.treenumber }}
37 </view> 48 </view>
38 </template> 49 </template>
39 -  
40 -<!-- <template #foot>-->  
41 -<!-- <view class="treenumber-no">-->  
42 -<!-- 树木编号:{{ i.treenumber }}-->  
43 -<!-- </view>-->  
44 -<!-- </template>-->  
45 </up-card> 50 </up-card>
46 </view> 51 </view>
47 - 52 + </z-paging>
48 <!-- 底部新增按钮 --> 53 <!-- 底部新增按钮 -->
49 <view class="fixed-bottom-btn-wrap"> 54 <view class="fixed-bottom-btn-wrap">
50 <up-button 55 <up-button
@@ -82,7 +87,8 @@ onLoad((options) =&gt; { @@ -82,7 +87,8 @@ onLoad((options) =&gt; {
82 }) 87 })
83 88
84 onShow(() => { 89 onShow(() => {
85 - treeRoadQuery() 90 + // 初始化分页数据
  91 + pagingRef.value?.reload()
86 }) 92 })
87 93
88 94
@@ -99,10 +105,12 @@ const toAddTreePage = () =&gt; { @@ -99,10 +105,12 @@ const toAddTreePage = () =&gt; {
99 }) 105 })
100 } 106 }
101 107
102 -const treeRoadQuery = async () => {  
103 - const res = await treeRoadReq( {road: roadId.value}) 108 +const pagingRef = ref(null) // z-paging实例
  109 +const fetchData = async (pageNo, pageSize) => {
  110 + const res = await treeRoadReq( {road: roadId.value,pageNo, pageSize})
104 console.log(res) 111 console.log(res)
105 - rows.value = res.list 112 + // rows.value = res.list
  113 + pagingRef.value?.complete(res?.list || [], res?.total)
106 } 114 }
107 </script> 115 </script>
108 116
pages/index/index.vue
@@ -88,7 +88,7 @@ @@ -88,7 +88,7 @@
88 <view class="task-item__footer u-flex common-item-center common-justify-between" 88 <view class="task-item__footer u-flex common-item-center common-justify-between"
89 style="font-size: 13px; margin-top: 5px;"> 89 style="font-size: 13px; margin-top: 5px;">
90 <view class="urgency-tag" > 90 <view class="urgency-tag" >
91 - 紧急程度: {{ item.pressingType }} 91 + 紧急程度: {{ item.pressingType||'--' }}
92 </view> 92 </view>
93 <view style="font-size: 13px;color: #333">{{ 93 <view style="font-size: 13px;color: #333">{{
94 timeFormat(item.busiDateTime, 'yyyy-mm-dd hh:MM:ss') 94 timeFormat(item.busiDateTime, 'yyyy-mm-dd hh:MM:ss')
@@ -371,7 +371,7 @@ $border-color: #e5e5e5; // 新增边框颜色变量 @@ -371,7 +371,7 @@ $border-color: #e5e5e5; // 新增边框颜色变量
371 .user-info-bar { 371 .user-info-bar {
372 background: url("https://img.jichengshanshui.com.cn:28207/appimg/bg.jpg") no-repeat; 372 background: url("https://img.jichengshanshui.com.cn:28207/appimg/bg.jpg") no-repeat;
373 background-size: 100% 100%; 373 background-size: 100% 100%;
374 - padding: 90px $spacing-lg 135px; 374 + padding: 80px $spacing-lg 135px;
375 display: flex; 375 display: flex;
376 justify-content: space-between; 376 justify-content: space-between;
377 align-items: center; 377 align-items: center;
pages/login/index.vue
1 <template> 1 <template>
2 - <view class="login-page"> 2 + <view class="page-container">
3 <!-- 顶部标题区 --> 3 <!-- 顶部标题区 -->
4 <view class="top-title"> 4 <view class="top-title">
5 <text class="welcome-text">你好,欢迎光临</text> 5 <text class="welcome-text">你好,欢迎光临</text>
@@ -112,27 +112,76 @@ @@ -112,27 +112,76 @@
112 import { ref, reactive, onMounted, nextTick } from 'vue'; 112 import { ref, reactive, onMounted, nextTick } from 'vue';
113 import { useUserStore } from '@/pinia/user'; 113 import { useUserStore } from '@/pinia/user';
114 import globalConfig from '@/common/config/global'; 114 import globalConfig from '@/common/config/global';
  115 +import CryptoJS from 'crypto-js';
  116 +
  117 +// ========== 加密工具函数(建议抽离到 @/utils/encrypt.js) ==========
  118 +// 密钥配置:生产环境建议从后端接口获取,不要硬编码
  119 +const CRYPTO_CONFIG = {
  120 + key: CryptoJS.enc.Utf8.parse('jcsscrypto123abc'), // 16位key(AES-128)
  121 + iv: CryptoJS.enc.Utf8.parse('abc123jcsscrypto'), // 16位iv
  122 + mode: CryptoJS.mode.CBC,
  123 + padding: CryptoJS.pad.Pkcs7
  124 +};
115 125
116 -// 全局实例 & 基础状态 126 +/**
  127 + * AES加密
  128 + * @param {string} text 待加密文本
  129 + * @returns {string} 加密后的字符串
  130 + */
  131 +const aesEncrypt = (text) => {
  132 + if (!text) return '';
  133 + try {
  134 + return CryptoJS.AES.encrypt(text, CRYPTO_CONFIG.key, {
  135 + iv: CRYPTO_CONFIG.iv,
  136 + mode: CRYPTO_CONFIG.mode,
  137 + padding: CRYPTO_CONFIG.padding
  138 + }).toString();
  139 + } catch (err) {
  140 + console.error('AES加密失败:', err);
  141 + return '';
  142 + }
  143 +};
  144 +
  145 +/**
  146 + * AES解密
  147 + * @param {string} encryptedText 加密后的字符串
  148 + * @returns {string} 解密后的原始文本
  149 + */
  150 +const aesDecrypt = (encryptedText) => {
  151 + if (!encryptedText) return '';
  152 + try {
  153 + const decryptObj = CryptoJS.AES.decrypt(encryptedText, CRYPTO_CONFIG.key, {
  154 + iv: CRYPTO_CONFIG.iv,
  155 + mode: CRYPTO_CONFIG.mode,
  156 + padding: CRYPTO_CONFIG.padding
  157 + });
  158 + return decryptObj.toString(CryptoJS.enc.Utf8);
  159 + } catch (err) {
  160 + console.error('AES解密失败:', err);
  161 + return '';
  162 + }
  163 +};
  164 +
  165 +// ========== 业务逻辑 ==========
117 const userStore = useUserStore(); 166 const userStore = useUserStore();
118 const loginFormRef = ref(null); 167 const loginFormRef = ref(null);
119 const isLoading = ref(false); 168 const isLoading = ref(false);
120 169
121 -// Tabs配置(name直接存储显示文本) 170 +// Tabs配置
122 const tabList = ref([ 171 const tabList = ref([
123 { name: '手机号登录' }, 172 { name: '手机号登录' },
124 { name: '账号登录' } 173 { name: '账号登录' }
125 ]); 174 ]);
126 -const loginType = ref('手机号登录'); // 登录类型标识 175 +const loginType = ref('手机号登录');
127 176
128 -// 记住密码(默认选中) 177 +// 记住密码
129 const rememberPwd = ref(true); 178 const rememberPwd = ref(true);
130 179
131 // 表单数据 180 // 表单数据
132 const form = reactive({ 181 const form = reactive({
133 - account: '', // 账号  
134 - mobile: '', // 手机号  
135 - password: '' // 密码 182 + account: '',
  183 + mobile: '',
  184 + password: ''
136 }); 185 });
137 186
138 // 表单校验规则 187 // 表单校验规则
@@ -152,56 +201,19 @@ const loginFormRules = reactive({ @@ -152,56 +201,19 @@ const loginFormRules = reactive({
152 }); 201 });
153 202
154 // Tabs切换事件 203 // Tabs切换事件
155 -const handleTabChange = ({name}) => {  
156 - console.log(name) 204 +const handleTabChange = ({ name }) => {
157 if (isLoading.value) return; 205 if (isLoading.value) return;
158 loginType.value = name; 206 loginType.value = name;
159 -  
160 - // 切换时清空另一类输入框  
161 if (name === '手机号登录') { 207 if (name === '手机号登录') {
162 form.account = ''; 208 form.account = '';
163 } else { 209 } else {
164 form.mobile = ''; 210 form.mobile = '';
165 } 211 }
166 -  
167 - // 清空校验状态  
168 nextTick(() => { 212 nextTick(() => {
169 loginFormRef.value?.clearValidate(); 213 loginFormRef.value?.clearValidate();
170 }); 214 });
171 }; 215 };
172 216
173 -// 生命周期  
174 -onMounted(() => {  
175 - // 检查登录态  
176 - checkLoginStatus();  
177 -  
178 - // 初始化表单校验规则  
179 - nextTick(() => {  
180 - loginFormRef.value?.setRules(loginFormRules);  
181 - });  
182 -  
183 - // 读取缓存的账号/密码  
184 - if (rememberPwd.value) {  
185 - try {  
186 - const savedAccount = uni.getStorageSync('login_account') || '';  
187 - const savedMobile = uni.getStorageSync('login_mobile') || '';  
188 - const savedPwd = uni.getStorageSync('login_password') || '';  
189 -  
190 - if (savedAccount) {  
191 - form.account = savedAccount;  
192 - loginType.value = '账号登录';  
193 -  
194 - } else if (savedMobile) {  
195 - form.mobile = savedMobile;  
196 - loginType.value = '手机号登录';  
197 - }  
198 - form.password = savedPwd;  
199 - } catch (err) {  
200 - console.warn('读取缓存密码失败:', err);  
201 - }  
202 - }  
203 -});  
204 -  
205 // 检查登录状态 217 // 检查登录状态
206 const checkLoginStatus = () => { 218 const checkLoginStatus = () => {
207 try { 219 try {
@@ -212,21 +224,19 @@ const checkLoginStatus = () =&gt; { @@ -212,21 +224,19 @@ const checkLoginStatus = () =&gt; {
212 }); 224 });
213 } 225 }
214 } catch (err) { 226 } catch (err) {
215 - console.warn('检查登录状态失败', err); 227 + console.warn('检查登录状态失败:', err);
216 } 228 }
217 }; 229 };
218 230
219 // 登录方法 231 // 登录方法
220 const handleLogin = async () => { 232 const handleLogin = async () => {
221 try { 233 try {
222 - // 表单校验  
223 await loginFormRef.value.validate(); 234 await loginFormRef.value.validate();
224 isLoading.value = true; 235 isLoading.value = true;
225 236
226 // 组装登录参数 237 // 组装登录参数
227 const loginParams = { password: form.password }; 238 const loginParams = { password: form.password };
228 if (loginType.value === '手机号登录') { 239 if (loginType.value === '手机号登录') {
229 - // loginParams.mobile = form.mobile;  
230 loginParams.username = form.mobile; 240 loginParams.username = form.mobile;
231 } else { 241 } else {
232 loginParams.username = form.account; 242 loginParams.username = form.account;
@@ -235,19 +245,20 @@ const handleLogin = async () =&gt; { @@ -235,19 +245,20 @@ const handleLogin = async () =&gt; {
235 // 执行登录 245 // 执行登录
236 await userStore.login(loginParams); 246 await userStore.login(loginParams);
237 247
238 - // 保存记住密码 248 + // 保存数据:账号/密码 均用AES加密
239 if (rememberPwd.value) { 249 if (rememberPwd.value) {
240 try { 250 try {
241 if (loginType.value === '手机号登录') { 251 if (loginType.value === '手机号登录') {
242 - uni.setStorageSync('login_mobile', form.mobile); 252 + uni.setStorageSync('login_mobile', aesEncrypt(form.mobile));
243 uni.removeStorageSync('login_account'); 253 uni.removeStorageSync('login_account');
244 } else { 254 } else {
245 - uni.setStorageSync('login_account', form.account); 255 + uni.setStorageSync('login_account', aesEncrypt(form.account));
246 uni.removeStorageSync('login_mobile'); 256 uni.removeStorageSync('login_mobile');
247 } 257 }
248 - uni.setStorageSync('login_password', form.password); 258 + // 密码加密存储(可解密还原)
  259 + uni.setStorageSync('login_password', aesEncrypt(form.password));
249 } catch (err) { 260 } catch (err) {
250 - console.warn('保存密码失败:', err); 261 + console.warn('保存登录信息失败:', err);
251 } 262 }
252 } else { 263 } else {
253 // 清除缓存 264 // 清除缓存
@@ -256,7 +267,7 @@ const handleLogin = async () =&gt; { @@ -256,7 +267,7 @@ const handleLogin = async () =&gt; {
256 uni.removeStorageSync('login_password'); 267 uni.removeStorageSync('login_password');
257 } 268 }
258 269
259 - // 登录成功提示+跳转 270 + // 登录成功跳转
260 uni.showToast({ title: '登录成功', icon: 'success', duration: 1000 }); 271 uni.showToast({ title: '登录成功', icon: 'success', duration: 1000 });
261 setTimeout(() => { 272 setTimeout(() => {
262 uni.switchTab({ 273 uni.switchTab({
@@ -265,9 +276,8 @@ const handleLogin = async () =&gt; { @@ -265,9 +276,8 @@ const handleLogin = async () =&gt; {
265 }); 276 });
266 }, 1000); 277 }, 1000);
267 } catch (err) { 278 } catch (err) {
268 - // 错误处理  
269 if (!Array.isArray(err)) { 279 if (!Array.isArray(err)) {
270 - console.error('登录失败', err); 280 + console.error('登录失败:', err);
271 uni.showToast({ 281 uni.showToast({
272 title: err.msg || '账号或密码错误,请重试', 282 title: err.msg || '账号或密码错误,请重试',
273 icon: 'none', 283 icon: 'none',
@@ -278,20 +288,39 @@ const handleLogin = async () =&gt; { @@ -278,20 +288,39 @@ const handleLogin = async () =&gt; {
278 isLoading.value = false; 288 isLoading.value = false;
279 } 289 }
280 }; 290 };
  291 +
  292 +// 生命周期
  293 +onMounted(() => {
  294 + checkLoginStatus();
  295 + // 初始化表单规则
  296 + nextTick(() => {
  297 + loginFormRef.value?.setRules(loginFormRules);
  298 + });
  299 + // 读取缓存并解密填充
  300 + if (rememberPwd.value) {
  301 + try {
  302 + const savedAccount = aesDecrypt(uni.getStorageSync('login_account') || '');
  303 + const savedMobile = aesDecrypt(uni.getStorageSync('login_mobile') || '');
  304 + const savedPwd = aesDecrypt(uni.getStorageSync('login_password') || '');
  305 +
  306 + if (savedAccount) {
  307 + form.account = savedAccount;
  308 + loginType.value = '账号登录';
  309 + } else if (savedMobile) {
  310 + form.mobile = savedMobile;
  311 + loginType.value = '手机号登录';
  312 + }
  313 + // 密码解密后填充到输入框(可展示)
  314 + form.password = savedPwd;
  315 + } catch (err) {
  316 + console.warn('读取缓存失败:', err);
  317 + }
  318 + }
  319 +});
281 </script> 320 </script>
282 321
283 <style scoped lang="scss"> 322 <style scoped lang="scss">
284 -// 核心布局  
285 -.login-page {  
286 - min-height: 100vh;  
287 - padding: 0;  
288 - box-sizing: border-box;  
289 - overflow: hidden;  
290 - position: relative;  
291 - background: #f5f7fa;  
292 -}  
293 323
294 -// 顶部样式  
295 .top-title { 324 .top-title {
296 background: url("https://img.jichengshanshui.com.cn:28207/appimg/bg.jpg") no-repeat; 325 background: url("https://img.jichengshanshui.com.cn:28207/appimg/bg.jpg") no-repeat;
297 background-size: 100% 100%; 326 background-size: 100% 100%;
@@ -327,7 +356,6 @@ const handleLogin = async () =&gt; { @@ -327,7 +356,6 @@ const handleLogin = async () =&gt; {
327 box-sizing: border-box; 356 box-sizing: border-box;
328 } 357 }
329 358
330 -// Tabs样式适配  
331 :deep(.u-tabs) { 359 :deep(.u-tabs) {
332 margin-bottom: 15px; 360 margin-bottom: 15px;
333 .u-tabs__content { 361 .u-tabs__content {
@@ -338,29 +366,24 @@ const handleLogin = async () =&gt; { @@ -338,29 +366,24 @@ const handleLogin = async () =&gt; {
338 } 366 }
339 } 367 }
340 368
341 -// 表单间距  
342 :deep(.u-form-item) { 369 :deep(.u-form-item) {
343 margin-bottom: 10px; 370 margin-bottom: 10px;
344 position: relative; 371 position: relative;
345 } 372 }
346 373
347 -// 密码项样式  
348 .password-item { 374 .password-item {
349 position: relative; 375 position: relative;
350 margin-bottom: 5px !important; 376 margin-bottom: 5px !important;
351 } 377 }
352 378
353 -// ✅ 核心优化:记住密码完全居右对齐  
354 .remember-wrap { 379 .remember-wrap {
355 - //text-align: right;  
356 - padding: 0; // 移除多余内边距 380 + padding: 0;
357 margin: 10px 0 20px; 381 margin: 10px 0 20px;
358 382
359 :deep(.u-checkbox) { 383 :deep(.u-checkbox) {
360 font-size: 12px; 384 font-size: 12px;
361 color: #666; 385 color: #666;
362 justify-content: flex-end; 386 justify-content: flex-end;
363 - // 移除复选框的默认左边距,确保居右紧凑  
364 margin-left: 0 !important; 387 margin-left: 0 !important;
365 388
366 .u-checkbox__label { 389 .u-checkbox__label {
@@ -369,7 +392,6 @@ const handleLogin = async () =&gt; { @@ -369,7 +392,6 @@ const handleLogin = async () =&gt; {
369 } 392 }
370 } 393 }
371 394
372 -// 登录按钮  
373 .login-btn { 395 .login-btn {
374 margin-top: 10px; 396 margin-top: 10px;
375 width: 100%; 397 width: 100%;
@@ -382,7 +404,6 @@ const handleLogin = async () =&gt; { @@ -382,7 +404,6 @@ const handleLogin = async () =&gt; {
382 border-radius: 23px; 404 border-radius: 23px;
383 } 405 }
384 406
385 -// 版权信息  
386 .copyright { 407 .copyright {
387 width: 100%; 408 width: 100%;
388 text-align: center; 409 text-align: center;
pages/mine/index.vue
@@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@
13 <view class="user-info-content"> 13 <view class="user-info-content">
14 <view class="user-name">{{ userStore.isLogin ? userInfo.username : '未登录' }}</view> 14 <view class="user-name">{{ userStore.isLogin ? userInfo.username : '未登录' }}</view>
15 <!-- <view class="user-phone">{{ userStore.isLogin ? userInfo.nickname : '&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;' }}</view>--> 15 <!-- <view class="user-phone">{{ userStore.isLogin ? userInfo.nickname : '&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;' }}</view>-->
16 - <view class="user-phone">上次登录时间{{ timeFormat(userInfo.loginDate)}}</view> 16 + <view class="user-phone">上次登录时间 {{ timeFormat(userInfo.loginDate)}}</view>
17 17
18 </view> 18 </view>
19 19
@@ -123,7 +123,7 @@ export default { @@ -123,7 +123,7 @@ export default {
123 top: 0; 123 top: 0;
124 left: 0; 124 left: 0;
125 width: 100%; 125 width: 100%;
126 - height: 230px; 126 + height: 220px;
127 //height: 120px; 127 //height: 120px;
128 background: url("https://img.jichengshanshui.com.cn:28207/appimg/bg.jpg") no-repeat; 128 background: url("https://img.jichengshanshui.com.cn:28207/appimg/bg.jpg") no-repeat;
129 background-size: 100% 100%; 129 background-size: 100% 100%;
@@ -160,17 +160,15 @@ export default { @@ -160,17 +160,15 @@ export default {
160 } 160 }
161 // 退出登录按钮 161 // 退出登录按钮
162 .logout-btn-wrap { 162 .logout-btn-wrap {
163 - margin: 100px 10px 10px; 163 + margin: 80px 15px 0;
164 } 164 }
165 // 登录按钮 165 // 登录按钮
166 .login-btn { 166 .login-btn {
167 - margin-top: 20px;  
168 width: 100%; 167 width: 100%;
169 height: 44px; 168 height: 44px;
170 line-height: 44px; 169 line-height: 44px;
171 border-radius: 4px; 170 border-radius: 4px;
172 font-size: 16px; 171 font-size: 16px;
173 -  
174 background: #0A86F4; 172 background: #0A86F4;
175 box-shadow: 0px 4px 6px 1px rgba(25,94,215,0.5); 173 box-shadow: 0px 4px 6px 1px rgba(25,94,215,0.5);
176 border-radius: 23px; 174 border-radius: 23px;
pages/workbench/index.vue
@@ -166,7 +166,7 @@ const handleMenuClick = (item: MenuItem) =&gt; { @@ -166,7 +166,7 @@ const handleMenuClick = (item: MenuItem) =&gt; {
166 top: 0; 166 top: 0;
167 left: 0; 167 left: 0;
168 width: 100%; 168 width: 100%;
169 - padding: 80px 15px 125px; 169 + padding: 80px 15px 115px;
170 background: url("https://img.jichengshanshui.com.cn:28207/appimg/bg.jpg") no-repeat; 170 background: url("https://img.jichengshanshui.com.cn:28207/appimg/bg.jpg") no-repeat;
171 background-size: 100% 100%; 171 background-size: 100% 100%;
172 z-index: 1; 172 z-index: 1;
@@ -176,7 +176,7 @@ const handleMenuClick = (item: MenuItem) =&gt; { @@ -176,7 +176,7 @@ const handleMenuClick = (item: MenuItem) =&gt; {
176 .welcome-text { 176 .welcome-text {
177 font-size: 16px; 177 font-size: 16px;
178 display: block; 178 display: block;
179 - margin-bottom: 10px; 179 + margin-bottom: 4px;
180 font-weight: 500; 180 font-weight: 500;
181 } 181 }
182 182
@@ -191,7 +191,7 @@ const handleMenuClick = (item: MenuItem) =&gt; { @@ -191,7 +191,7 @@ const handleMenuClick = (item: MenuItem) =&gt; {
191 .content-wrap { 191 .content-wrap {
192 position: relative; 192 position: relative;
193 z-index: 2; 193 z-index: 2;
194 - padding: 135px 0 0; 194 + padding: 125px 0 0;
195 display: flex; 195 display: flex;
196 flex-direction: column; 196 flex-direction: column;
197 gap: 10px; 197 gap: 10px;