From da05dcffeabcb3c460e45666a4804f4ea5a4145a Mon Sep 17 00:00:00 2001
From: zhou zhou <3272660260@qq.com>
Date: 星期三, 25 二月 2026 17:02:17 +0800
Subject: [PATCH] #

---
 pages/home/home.vue                       |  579 ++++++++++++++
 .gemini/skills/wms-dev-standards/SKILL.md |   62 +
 pages/login/login.vue                     |  934 ++++++++++++++--------
 locale/zh-Hans.json                       |   16 
 pages.json                                |    4 
 .trae/skills/nvue/SKILL.md                |   63 +
 config/request.js                         |   86 ++
 locale/en.json                            |   14 
 pages/login/api.js                        |    7 
 /dev/null                                 |   41 -
 pages/login/index.nvue                    |  559 +++++++++++++
 main.js                                   |   16 
 pages/home/api.js                         |    4 
 pages/index/index.vue                     |   33 
 14 files changed, 2,004 insertions(+), 414 deletions(-)

diff --git a/.gemini/skills/wms-dev-standards/SKILL.md b/.gemini/skills/wms-dev-standards/SKILL.md
new file mode 100644
index 0000000..7be4f2c
--- /dev/null
+++ b/.gemini/skills/wms-dev-standards/SKILL.md
@@ -0,0 +1,62 @@
+---
+name: wms-dev-standards
+description: Guidance for developing the WMS uniapp project. Use this when writing new API requests or developing UI components to ensure consistency with uView UI and existing API request patterns.
+---
+
+# WMS Project Development Standards
+
+This skill outlines the core development standards and patterns to follow when contributing to the WMS uniapp project.
+
+## API Request Pattern
+
+When adding or modifying API requests, always follow the established pattern in `config/api.js`.
+
+### Core Rules
+
+1. **HTTP Client:** Always use `uni.$u.http` for requests.
+2. **Export Format:** Export each API call as a named arrow function.
+3. **GET Parameters:** When sending parameters in a `GET` request, they **must** be wrapped in a configuration object with a `params` key.
+
+### Examples
+
+**Correct GET Request (with parameters):**
+```javascript
+import { http } from '@/config/api.js' // or standard uniapp import
+
+const http = uni.$u.http
+
+// 鐢ㄦ埛鐧诲綍 - Wrap parameters in { params }
+export const login = (params) => http.get('/login.action', { params })
+```
+
+**Correct POST Request:**
+```javascript
+// POST requests pass data directly as the second argument
+export const submitData = (data) => http.post('/submit.action', data)
+```
+
+## UI Component Standards
+
+The project relies exclusively on the **uView UI** library for its components.
+
+### Core Rules
+
+1. **Use uView Components:** Always prefer uView components (e.g., `<u-button>`, `<u-input>`, `<u-form>`) over native components (`<button>`, `<input>`) or writing custom CSS when a uView equivalent exists.
+2. **Consult Available Components:** The project already has `uview-ui` installed. Check the existing component library capabilities before writing custom layouts.
+3. **Styling:** Follow the existing project styling classes and `uni.scss` variables where appropriate.
+
+### Examples
+
+**Correct UI implementation:**
+```vue
+<template>
+  <view class="container">
+    <u--form>
+      <u-form-item label="Username">
+        <u--input v-model="username" placeholder="Enter your username"></u--input>
+      </u-form-item>
+      <u-button type="primary" @click="handleLogin">Login</u-button>
+    </u--form>
+  </view>
+</template>
+```
diff --git a/.trae/skills/nvue/SKILL.md b/.trae/skills/nvue/SKILL.md
new file mode 100644
index 0000000..c470b88
--- /dev/null
+++ b/.trae/skills/nvue/SKILL.md
@@ -0,0 +1,63 @@
+---
+name: "nvue"
+description: "Expert assistant for uni-app nvue (native rendering) development. Invoke when working with .nvue files, native rendering, or performance optimization in uni-app."
+---
+
+# Uni-app nvue Development Skill
+
+You are an expert in uni-app nvue (native vue) development. nvue uses a native rendering engine based on Weex, distinct from the WebView-based Vue pages.
+
+## Core Principles
+1.  **Environment**: Assumes latest HBuilderX version.
+2.  **Native Rendering**: nvue maps to native components. It is NOT a webview.
+3.  **Strict Layout**: ONLY Flexbox is supported.
+4.  **Text Rendering**: All text MUST be wrapped in `<text>` components.
+5.  **Compilation Mode**: In `uni-app` mode (default), styles from `App.vue` are compiled into every `.nvue` file.
+
+## When to Use nvue
+Recommend nvue for:
+-   **High Performance Lists**: `list`, `recycle-list`, `waterfall`.
+-   **Complex Interactions**: `BindingX` for high-performance gestures/animations.
+-   **Complex Layouts**: Left/right draggable lists, sticky headers + swiper.
+-   **Native Component Coverage**: Overcoming z-index issues with `map`, `video`, `live-pusher`.
+-   **Fast Startup**: nvue pages load faster than WebView pages.
+
+## CSS Limitations & Rules
+-   **Layout**: `display: flex` is default and only option. No `grid`, `block`, `inline-block`.
+-   **Box Model**: Defaults to `border-box`.
+-   **Text**:
+    -   Must use `<text>Content</text>`.
+    -   Only `<text>` supports `font-size`, `color`, `lines` (truncation).
+    -   `<text>` cannot contain other components.
+-   **Styling**:
+    -   **Supported Shorthands**: `border`, `border-top` (etc), `border-radius`, `flex-flow`, `background`.
+    -   **Supported Selectors**: Class selectors, descendant, child, adjacent sibling, and general sibling selectors.
+    -   **Class Binding**: Only array syntax `:class="['a', 'b']"` is supported. Object syntax is NOT supported.
+    -   **Units**: No `%` (mostly). Use `px` (logic pixels) or `rpx`.
+    -   **Background**: `background-image` is NOT supported in CSS. Use `<image>` component with `position: absolute`.
+    -   **Transparency**: Android components are transparent by default. Set `background-color` to avoid ghosting.
+    -   **Overflow**: Android only supports `hidden`. iOS supports `hidden` and `visible`.
+
+## API Usage
+-   **DOM Module**:
+    -   `dom.addRule('fontFace', { fontFamily: '...', src: "url('...')" })`
+    -   `dom.scrollToElement(ref, { offset: 0 })`
+    -   `dom.getComponentRect(ref, callback)` (Use ref `'viewport'` for screen dims).
+-   **Native Plugins**:
+    -   `const plugin = uni.requireNativePlugin('PluginName')`
+    -   **BindingX**: Built-in for high-performance expression binding.
+    -   **Animation**: `uni.requireNativePlugin('animation')`.
+-   **Transition**: Supports `width`, `height`, `backgroundColor`, `opacity`, `transform`.
+
+## Event Handling
+-   **Events**: `click`, `longpress`, `appear` (view becomes visible), `disappear`.
+    -   `appear`/`disappear` provide `direction` (up/down).
+-   **Event Penetration (iOS)**: `<view eventPenetrationEnabled="true">` allows clicks to pass through to underlying layers.
+-   **User Interaction (iOS)**: `<view userInteractionEnabled="false">` disables all interaction.
+
+## Code Generation Guidelines
+1.  Always verify if the file is `.nvue`.
+2.  If user asks for CSS that is invalid in nvue (e.g., `background-image`, `display: grid`), STOP and explain the limitation, then provide the nvue-compatible workaround.
+3.  Use `<list>` or `<waterfall>` for long lists instead of `<scroll-view>` for better performance.
+4.  Ensure all text nodes are strictly inside `<text>`.
+5.  Prefer `BindingX` for complex touch interactions.
diff --git a/common/request.js b/common/request.js
deleted file mode 100644
index b3caf91..0000000
--- a/common/request.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/**
- * @param {string} url url鍦板潃
- * @param {any} postData 鍙傛暟
- * @param {string} method 璇锋眰鏂瑰紡
- * @param {boolean} hideLoading 鏄惁load
- * @description: 鏍煎紡鍖栨椂闂�
- */
-export function request(url, postData, method = 'POST', hideLoading = 'false') {
-	if (!hideLoading) {
-		uni.showLoading({
-			title: '璇风◢鍊�...',
-			mask: true
-		})
-	}
-	return new Promise((resolve, reject) => {
-		const token = uni.getStorageSync('token');
-		// const URL = 'http://47.76.147.249:8080/rsf-server/pda' + url;
-		// const URL = 'http://test.zoneyung.net:8080/rsf-server/pda' + url;
-		const URL = 'http://127.0.0.1:8080/jshdasrs/' + url;
-		uni.request({
-			url: URL,
-			data: postData,
-			header: {
-				'content-type': 'application/json',
-				'token': token
-			},
-			method: method, //'GET','POST'
-			dataType: 'json',
-			success: (res) => {
-				!hideLoading && uni.hideLoading()
-				resolve(res.data)
-
-			},
-			fail: (res) => {
-				// !hideLoading && toast("缃戠粶涓嶇粰鍔涳紝璇风◢鍚庡啀璇晘")
-				//wx.hideLoading()
-				reject(res)
-			}
-		})
-	})
-}
\ No newline at end of file
diff --git a/config/request.js b/config/request.js
new file mode 100644
index 0000000..9a8beab
--- /dev/null
+++ b/config/request.js
@@ -0,0 +1,86 @@
+// 姝m鍙傛暟涓洪〉闈㈢殑瀹炰緥锛屽彲浠ラ�氳繃瀹冨紩鐢╲uex涓殑鍙橀噺
+module.exports = (vm) => {
+	// 鍒濆鍖栬姹傞厤缃�
+	uni.$u.http.setConfig((config) => {
+		/* config 涓洪粯璁ゅ叏灞�閰嶇疆*/
+		// 鍔ㄦ�佽缃� baseURL
+		let settings = uni.getStorageSync('app_settings');
+		if (!settings) {
+			settings = {
+				ip: '127.0.0.1',
+				port: '8080',
+				project: 'jshdasrs'
+			};
+			// uni.setStorageSync('app_settings', settings);
+		}
+		config.baseURL = `http://${settings.ip}:${settings.port}/${settings.project}`;
+		config.header = {
+			'content-type': 'application/json'
+		};
+		return config;
+	})
+
+	// 璇锋眰鎷︽埅
+	uni.$u.http.interceptors.request.use((config) => { // 鍙娇鐢╝sync await 鍋氬紓姝ユ搷浣�
+		// 鍒濆鍖栬姹傛嫤鎴櫒鏃讹紝浼氭墽琛屾鏂规硶锛屾鏃禿ata涓簎ndefined锛岃祴浜堥粯璁}
+		config.data = config.data || {}
+
+		// 鎻愮ず鍔犺浇妗嗛�昏緫锛堟牴鎹� custom.hideLoading 鍐冲畾锛�
+		const hideLoading = config.custom?.hideLoading;
+		if (hideLoading === false || hideLoading === undefined) {
+			uni.showLoading({
+				title: '璇风◢鍊�...',
+				mask: true
+			});
+		}
+
+		// 鏍规嵁custom鍙傛暟涓厤缃殑鏄惁闇�瑕乼oken锛屾坊鍔犲搴旂殑璇锋眰澶�
+		// 榛樿鎴栨樉寮� auth 涓� true 鏃舵坊鍔� token
+		if (config?.custom?.auth !== false) {
+			const token = uni.getStorageSync('token');
+			if (token) {
+				config.header.token = token;
+			}
+		}
+		return config
+	}, config => { // 鍙娇鐢╝sync await 鍋氬紓姝ユ搷浣�
+		return Promise.reject(config)
+	})
+
+	// 鍝嶅簲鎷︽埅
+	uni.$u.http.interceptors.response.use((response) => {
+		/* 瀵瑰搷搴旀垚鍔熷仛鐐逛粈涔� 鍙娇鐢╝sync await 鍋氬紓姝ユ搷浣�*/
+		const hideLoading = response.config?.custom?.hideLoading;
+		if (hideLoading === false || hideLoading === undefined) {
+			uni.hideLoading();
+		}
+
+		const data = response.data
+		// 鑷畾涔夊弬鏁�
+		const custom = response.config?.custom || {}
+
+		if (data.code !== 200) {
+			// 濡傛灉娌℃湁鏄惧紡瀹氫箟custom鐨則oast鍙傛暟涓篺alse鐨勮瘽锛岄粯璁ゅ鎶ラ敊杩涜toast寮瑰嚭鎻愮ず
+			if (custom.toast !== false) {
+				uni.$u.toast(data.msg || data.message || '璇锋眰澶辫触')
+			}
+
+			// 濡傛灉闇�瑕乧atch杩斿洖锛屽垯杩涜reject
+			if (custom?.catch) {
+				return Promise.reject(data)
+			} else {
+				// 鍚﹀垯杩斿洖涓�涓猵ending涓殑promise锛岃姹備笉浼氳繘鍏atch涓�
+				return new Promise(() => {})
+			}
+		}
+		// 鏍规嵁绀轰緥锛岃繑鍥炰笟鍔℃暟鎹�
+		return data === undefined ? {} : data
+	}, (response) => {
+		// 瀵瑰搷搴旈敊璇仛鐐逛粈涔� 锛坰tatusCode !== 200锛�
+		const hideLoading = response.config?.custom?.hideLoading;
+		if (hideLoading === false || hideLoading === undefined) {
+			uni.hideLoading();
+		}
+		return Promise.reject(response)
+	})
+}
\ No newline at end of file
diff --git a/locale/en.json b/locale/en.json
index a960e47..0499039 100644
--- a/locale/en.json
+++ b/locale/en.json
@@ -41,5 +41,19 @@
   },
   "other":{
 	  
+  },
+  "settings": {
+  	"title": "Settings",
+  	"ip": "IP Address",
+  	"port": "Port",
+  	"project": "Project Name",
+  	"saved": "Settings Saved",
+  	"authTitle": "Authentication",
+  	"inputAuthPwd": "Enter Admin Password",
+  	"authError": "Incorrect Password"
+  },
+  "common": {
+  	"confirm": "Confirm",
+  	"cancel": "Cancel"
   }
 }
diff --git a/locale/zh-Hans.json b/locale/zh-Hans.json
index ff7223c..05d1cd3 100644
--- a/locale/zh-Hans.json
+++ b/locale/zh-Hans.json
@@ -43,7 +43,19 @@
 	"other":{
 		"asnNo":"ASN鍗曞彿"
 		
+	},
+	"settings": {
+		"title": "璁剧疆",
+		"ip": "IP鍦板潃",
+		"port": "绔彛",
+		"project": "椤圭洰鍚�",
+		"saved": "璁剧疆宸蹭繚瀛�",
+		"authTitle": "韬唤楠岃瘉",
+		"inputAuthPwd": "璇疯緭鍏ョ鐞嗗憳瀵嗙爜",
+		"authError": "瀵嗙爜閿欒"
+	},
+	"common": {
+		"confirm": "纭",
+		"cancel": "鍙栨秷"
 	}
-	
-	
 }
diff --git a/main.js b/main.js
index 6e0bb1c..c04e6b7 100644
--- a/main.js
+++ b/main.js
@@ -11,27 +11,35 @@
 import './uni.promisify.adaptor'
 Vue.config.productionTip = false
 App.mpType = 'app'
+
 import VueI18n from 'vue-i18n'
 Vue.use(VueI18n)
+
+import uView from '@/uni_modules/uview-ui'
+Vue.use(uView)
+
 const i18n = new VueI18n(i18nConfig)
 const app = new Vue({
 	...App,
 	i18n
 })
+
+// 寮曞叆璇锋眰灏佽锛屽皢app鍙傛暟浼犻�掑埌閰嶇疆涓�
+require('./config/request.js')(app)
+
 app.$mount()
 // #endif
-
-import uView from '@/uni_modules/uview-ui'
-Vue.use(uView)
 
 // #ifdef VUE3
 import {
 	createSSRApp
 } from 'vue'
+import uView from '@/uni_modules/uview-ui'
 export function createApp() {
 	const app = createSSRApp(App)
+	app.use(uView)
 	return {
 		app
 	}
 }
-// #endif
\ No newline at end of file
+// #endif
diff --git a/pages.json b/pages.json
index 7a73fbd..68e489c 100644
--- a/pages.json
+++ b/pages.json
@@ -1,6 +1,5 @@
 {
 	"pages": [ //pages鏁扮粍涓涓�椤硅〃绀哄簲鐢ㄥ惎鍔ㄩ〉锛屽弬鑰冿細https://uniapp.dcloud.io/collocation/pages
-
 		{
 			"path": "pages/login/login",
 			"style": {
@@ -9,10 +8,11 @@
 			}
 		},
 		{
-			"path": "pages/index/index",
+			"path": "pages/home/home",
 			"style": {
 				"navigationBarTitleText": "棣栭〉",
 				"navigationStyle": "custom"
+
 			}
 		},
 		{
diff --git a/pages/home/api.js b/pages/home/api.js
new file mode 100644
index 0000000..a4584cc
--- /dev/null
+++ b/pages/home/api.js
@@ -0,0 +1,4 @@
+const http = uni.$u.http
+
+// 鑾峰彇鍔ㄦ�佽彍鍗�
+export const getAuthMenu = (data, config = {}) => http.post('/menu/pda/auth', data, config)
diff --git a/pages/home/home.vue b/pages/home/home.vue
new file mode 100644
index 0000000..4d8ad18
--- /dev/null
+++ b/pages/home/home.vue
@@ -0,0 +1,579 @@
+<template>
+	<view class="page-container">
+		<!-- 澶撮儴瀵艰埅 -->
+		<u-navbar
+			title="Zoneyung 宸ヤ綔鍙�"
+			:fixed="true"
+			:placeholder="true"
+			bgColor="#ffffff"
+			titleStyle="font-weight: 600; color: #303133; font-size: 32rpx;"
+			leftIcon=""
+		></u-navbar>
+
+		<!-- 娆㈣繋淇℃伅 / 鐢ㄦ埛淇℃伅 -->
+		<view class="welcome-box">
+			<view class="welcome-info">
+				<text class="greeting">娆㈣繋鍥炴潵</text>
+				<text class="date-text">涓壃绔嬪簱 WMS 浠撳偍绠$悊绯荤粺</text>
+			</view>
+			<view class="welcome-avatar">
+				<!-- 鍙浛鎹负鐪熷疄澶村儚 -->
+				<u-avatar
+					icon="account-fill"
+					fontSize="24"
+					randomBgColor
+					size="45"
+				></u-avatar>
+			</view>
+		</view>
+
+		<!-- 鍔熻兘鑿滃崟 -->
+		<view class="menu-section">
+			<!-- 鍒嗙被妯″紡 -->
+			<template v-if="useCategoryMode">
+				<view
+					class="category-panel"
+					v-for="(category, catIndex) in categorizedMenus"
+					:key="category.key"
+				>
+					<view
+						class="category-header"
+						@click="toggleCategory(category.key)"
+					>
+						<view class="category-title-wrapper">
+							<view class="title-indicator"></view>
+							<text class="category-title">
+								{{ category.name }}
+							</text>
+						</view>
+						<view class="category-action">
+							<uni-icons
+								:type="
+									expandedCategories.includes(category.key)
+										? 'up'
+										: 'down'
+								"
+								size="16"
+								color="#909399"
+							></uni-icons>
+						</view>
+					</view>
+
+					<view
+						class="category-body"
+						v-show="expandedCategories.includes(category.key)"
+					>
+						<u-grid
+							:col="4"
+							:border="false"
+						>
+							<u-grid-item
+								v-for="(item, index) in category.items"
+								:key="index"
+								@click="navigateTo(item)"
+								customStyle="padding-top: 15px; padding-bottom: 15px;"
+							>
+								<view
+									class="grid-icon-box"
+									:style="{
+										backgroundColor: getBgColor(item.color)
+									}"
+								>
+									<uni-icons
+										:type="getIconType(item)"
+										size="24"
+										color="#ffffff"
+									></uni-icons>
+								</view>
+								<text class="grid-text">{{ item.title }}</text>
+							</u-grid-item>
+						</u-grid>
+					</view>
+				</view>
+
+				<!-- 鏈垎绫昏彍鍗� -->
+				<view
+					class="category-panel"
+					v-if="uncategorizedMenus.length > 0"
+				>
+					<view class="category-header">
+						<view class="category-title-wrapper">
+							<view class="title-indicator"></view>
+							<text class="category-title">鍏朵粬鎿嶄綔</text>
+						</view>
+					</view>
+					<view class="category-body">
+						<u-grid
+							:col="4"
+							:border="false"
+						>
+							<u-grid-item
+								v-for="(item, index) in uncategorizedMenus"
+								:key="index"
+								@click="navigateTo(item)"
+								customStyle="padding-top: 15px; padding-bottom: 15px;"
+							>
+								<view
+									class="grid-icon-box"
+									:style="{
+										backgroundColor: getBgColor(item.color)
+									}"
+								>
+									<uni-icons
+										:type="getIconType(item)"
+										size="24"
+										color="#ffffff"
+									></uni-icons>
+								</view>
+								<text class="grid-text">{{ item.title }}</text>
+							</u-grid-item>
+						</u-grid>
+					</view>
+				</view>
+			</template>
+
+			<!-- 骞抽摵妯″紡 -->
+			<template v-else>
+				<view class="category-panel">
+					<view class="category-body">
+						<u-grid
+							:col="4"
+							:border="false"
+						>
+							<u-grid-item
+								v-for="(item, index) in elements"
+								:key="index"
+								@click="navigateTo(item)"
+								customStyle="padding-top: 15px; padding-bottom: 15px;"
+							>
+								<view
+									class="grid-icon-box"
+									:style="{
+										backgroundColor: getBgColor(item.color)
+									}"
+								>
+									<uni-icons
+										:type="getIconType(item)"
+										size="24"
+										color="#ffffff"
+									></uni-icons>
+								</view>
+								<text class="grid-text">{{ item.title }}</text>
+							</u-grid-item>
+						</u-grid>
+					</view>
+				</view>
+			</template>
+		</view>
+
+		<!-- 搴曢儴鐗堟潈 -->
+		<view class="footer">
+			<text class="footer-text">
+				copyright 漏 2022 娴欐睙涓壃绔嬪簱鏈夐檺鍏徃 all rights reserved.
+			</text>
+		</view>
+	</view>
+</template>
+
+<script>
+import { getAuthMenu } from './api.js'
+
+export default {
+	data() {
+		return {
+			baseUrl: '',
+			token: '',
+			icon: '',
+			elements: [],
+			// 鏄惁浣跨敤鍒嗙被妯″紡锛坱rue: 涓婁笅灞傛姌鍙犺彍鍗曟ā寮�, false: 骞抽摵鑿滃崟妯″紡锛�
+			useCategoryMode: true,
+			// 榛樿鑿滃崟鏁版嵁锛堢敤浜庡悗绔棤杩斿洖鏃讹級
+			elements2: [
+				{
+					title: '缁勬墭',
+					name: 'pakin',
+					color: 'cyan',
+					cuIcon: 'pullup',
+					url: '/pakin/pakin'
+				},
+				{
+					title: '璁㈠崟鍏ュ簱',
+					name: 'orderPakin',
+					color: 'purple',
+					cuIcon: '',
+					url: '/order/orderList'
+				},
+				{
+					title: 'AGV瀹瑰櫒鍏ュ簱',
+					name: 'agv_start',
+					color: 'blue',
+					cuIcon: '',
+					url: '/AGV/agv_start'
+				},
+				{
+					title: 'AGV瀹瑰櫒鍥炲簱',
+					name: 'agv_back',
+					color: 'orange',
+					cuIcon: '',
+					url: '/AGV/agv_back'
+				},
+				{
+					title: '搴撳瓨鏌ヨ',
+					name: 'stockQuery',
+					color: 'green',
+					cuIcon: '',
+					url: '/stock/stockQuery'
+				},
+				{
+					title: '閫�鍑虹櫥褰�',
+					name: 'logOut',
+					color: 'grey',
+					cuIcon: 'exit',
+					url: '/login/logOut'
+				}
+			],
+			colorList: [
+				'cyan',
+				'purple',
+				'blue',
+				'pink',
+				'orange',
+				'green',
+				'mauve',
+				'brown',
+				'olive',
+				'red',
+				'yellow',
+				'grey'
+			],
+			// 鍥炬爣鏄犲皠
+			iconMap: {
+				pakin: 'upload',
+				orderPakin: 'list',
+				stockQuery: 'search',
+				logOut: 'redo',
+				orderPutOn: 'top',
+				orderPutDown: 'bottom',
+				restock: 'refresh',
+				stockCheck: 'checkbox',
+				agv_start: 'navigate',
+				agv_back: 'refresh'
+			},
+			// 鑿滃崟鍒嗙被閰嶇疆锛堜粎鍒嗙被妯″紡浣跨敤锛�
+			// key: 鍒嗙被鍞竴鏍囪瘑
+			// name: 鍒嗙被鏄剧ず鍚嶇О
+			// color: 鍒嗙被鍥炬爣棰滆壊
+			// icon: 鍒嗙被鍥炬爣
+			// menuNames: 璇ュ垎绫诲寘鍚殑鑿滃崟name鍒楄〃
+			categoryConfig: [
+				{
+					key: 'pakin_category',
+					name: '鍏ュ簱绠$悊',
+					color: 'cyan',
+					icon: 'upload',
+					menuNames: ['pakin', 'orderPakin']
+				},
+				{
+					key: 'agv_category',
+					name: 'AGV绠$悊',
+					color: 'blue',
+					icon: 'navigate',
+					menuNames: ['agv_start', 'agv_back']
+				},
+				{
+					key: 'stock_category',
+					name: '搴撳瓨绠$悊',
+					color: 'green',
+					icon: 'search',
+					menuNames: ['stockQuery']
+				}
+			],
+			// 涓嶅弬涓庡垎绫荤殑鑿滃崟椤癸紙濡傞��鍑虹櫥褰曪紝濮嬬粓鍗曠嫭鏄剧ず锛�
+			excludeFromCategory: ['logOut'],
+			// 褰撳墠灞曞紑鐨勫垎绫诲垪琛�
+			expandedCategories: [
+				'pakin_category',
+				'agv_category',
+				'stock_category'
+			]
+		}
+	},
+	computed: {
+		// 鍒嗙被鍚庣殑鑿滃崟鏁版嵁锛堣繃婊ゆ帀绌哄垎绫伙級
+		categorizedMenus() {
+			return this.categoryConfig
+				.map((category) => {
+					const items = this.elements.filter((item) =>
+						category.menuNames.includes(item.name)
+					)
+					return {
+						...category,
+						items: items
+					}
+				})
+				.filter((category) => category.items.length > 0)
+		},
+		// 鏈垎绫荤殑鑿滃崟锛堜笉鍦ㄤ换浣曞垎绫讳腑鎴栧湪鎺掗櫎鍒楄〃涓級
+		uncategorizedMenus() {
+			const allCategorizedNames = this.categoryConfig.reduce(
+				(acc, c) => acc.concat(c.menuNames || []),
+				[]
+			)
+			return this.elements.filter(
+				(item) =>
+					!allCategorizedNames.includes(item.name) ||
+					this.excludeFromCategory.includes(item.name)
+			)
+		}
+	},
+	onShow() {
+		this.baseUrl = uni.getStorageSync('baseUrl')
+		this.token = uni.getStorageSync('token')
+		this.getAuth()
+	},
+	methods: {
+		// 鍒囨崲鍒嗙被灞曞紑/鏀惰捣
+		toggleCategory(categoryKey) {
+			const index = this.expandedCategories.indexOf(categoryKey)
+			if (index > -1) {
+				this.expandedCategories.splice(index, 1)
+			} else {
+				this.expandedCategories.push(categoryKey)
+			}
+		},
+		// 鑾峰彇鍥炬爣绫诲瀷
+		getIconType(item) {
+			return this.iconMap[item.name] || 'circle'
+		},
+		// 棰滆壊鏄犲皠鍒板浘鐗囦笂鐨勪紒涓氳壊
+		getBgColor(colorStr) {
+			const map = {
+				cyan: '#00ced1',
+				purple: '#8a2be2',
+				blue: '#409eff',
+				pink: '#ff49db',
+				orange: '#e6a23c',
+				green: '#67c23a',
+				mauve: '#b070cc',
+				brown: '#874d28',
+				olive: '#8e9e30',
+				red: '#f56c6c',
+				yellow: '#e6a23c',
+				grey: '#909399'
+			}
+			return map[colorStr] || '#409eff'
+		},
+		// 璺宠浆椤甸潰
+		navigateTo(item) {
+			if (item.name === 'logOut') {
+				uni.reLaunch({
+					url: '/pages/login/login'
+				})
+				return
+			}
+			uni.navigateTo({
+				url: '/pages' + item.url
+			})
+		},
+		async getAuth() {
+			try {
+				// custom.catch=true ensures errors throw into the catch block
+				// custom.toast=false disables the interceptor's default toast so we can handle it manually
+				const res = await getAuthMenu(
+					{},
+					{ custom: { catch: true, toast: false } }
+				)
+				this.elements = []
+
+				if (
+					res.data == undefined ||
+					res.data == null ||
+					res.data === ''
+				) {
+					this.elements = this.elements2
+					return
+				}
+
+				for (let i = 0; i < res.data.length; i++) {
+					this.getIcon(res.data[i].title)
+					this.elements.unshift({
+						title: res.data[i].name,
+						name: res.data[i].title,
+						color: this.colorList[i % this.colorList.length],
+						cuIcon: this.icon,
+						url: res.data[i].action
+					})
+				}
+
+				this.elements.push({
+					title: '閫�鍑虹櫥褰�',
+					name: 'logOut',
+					color: 'grey',
+					cuIcon: 'exit',
+					url: '/login/logOut'
+				})
+			} catch (err) {
+				console.log('getAuth error:', err)
+				this.elements = this.elements2 // Fallback to default menus
+
+				const errCode = err.code || err.statusCode
+				const errMsg =
+					err.msg ||
+					err.message ||
+					(err.data && (err.data.msg || err.data.message))
+
+				if (errCode === 403) {
+					uni.showToast({
+						title: errMsg || '鏃犳潈闄愭垨鐧诲綍杩囨湡',
+						icon: 'none',
+						position: 'top'
+					})
+					setTimeout(() => {
+						uni.reLaunch({
+							url: '../login/login'
+						})
+					}, 1000)
+				} else {
+					if (errMsg) {
+						uni.showToast({
+							title: errMsg,
+							icon: 'none',
+							position: 'top'
+						})
+					}
+				}
+			}
+		},
+		getIcon(e) {
+			const ways = ['pakin', 'orderPakin', 'orderPutOn']
+			if (ways.includes(e)) {
+				this.icon = 'pullup'
+			}
+		}
+	}
+}
+</script>
+
+<style>
+page {
+	background: #f0f2f5; /* 绫讳技鍥剧墖涓祬鐏扮櫧鐨勫伐浣滃尯鑳屾櫙 */
+}
+
+.page-container {
+	min-height: 100vh;
+	background-color: #f0f2f5;
+}
+
+/* 娆㈣繋鍖哄煙 */
+.welcome-box {
+	background-color: #ffffff;
+	padding: 40rpx 40rpx;
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+	margin-bottom: 24rpx;
+	border-bottom: 1px solid #ebeef5; /* 杞诲井杈规 */
+}
+
+.welcome-info {
+	display: flex;
+	flex-direction: column;
+}
+
+.greeting {
+	font-size: 36rpx;
+	color: #303133;
+	font-weight: 600;
+	margin-bottom: 8rpx;
+}
+
+.date-text {
+	font-size: 26rpx;
+	color: #909399;
+}
+
+/* 鑿滃崟鍖哄煙 */
+.menu-section {
+	padding: 0 24rpx;
+}
+
+/* 鍒嗙被闈㈡澘椋庢牸锛氭磥鐧斤紝杞婚噺闃村奖/杈规 */
+.category-panel {
+	background-color: #ffffff;
+	border-radius: 12rpx;
+	margin-bottom: 24rpx;
+	overflow: hidden;
+	box-shadow: 0 2rpx 12rpx 0 rgba(0, 0, 0, 0.05); /* Element UI 甯哥敤娴呴槾褰� */
+}
+
+.category-header {
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+	padding: 30rpx 24rpx;
+	border-bottom: 1px solid #ebeef5;
+	background-color: #fafafa; /* 杞诲井鑳屾櫙鍖哄垎 */
+}
+
+.category-title-wrapper {
+	display: flex;
+	align-items: center;
+}
+
+/* 鏍囬宸︿晶鍨傜洿钃濊壊鎸囩ず绾� */
+.title-indicator {
+	width: 6rpx;
+	height: 30rpx;
+	background-color: #409eff;
+	border-radius: 4rpx;
+	margin-right: 16rpx;
+}
+
+.category-title {
+	font-size: 30rpx;
+	color: #303133;
+	font-weight: 600;
+}
+
+.category-action {
+	display: flex;
+	align-items: center;
+}
+
+.category-body {
+	padding: 10rpx 0;
+}
+
+/* 鑿滃崟涔濆鏍奸」 */
+.grid-icon-box {
+	width: 88rpx;
+	height: 88rpx;
+	border-radius: 50%;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	margin-bottom: 16rpx;
+	transition: transform 0.2s;
+}
+
+.grid-icon-box:active {
+	transform: scale(0.9);
+}
+
+.grid-text {
+	font-size: 26rpx;
+	color: #606266;
+	margin-top: 10rpx;
+}
+
+/* 搴曢儴 */
+.footer {
+	padding: 40rpx 0;
+	text-align: center;
+}
+
+.footer-text {
+	font-size: 24rpx;
+	color: #c0c4cc;
+}
+</style>
diff --git a/pages/index/index.vue b/pages/index/index.vue
index 729371f..4027174 100644
--- a/pages/index/index.vue
+++ b/pages/index/index.vue
@@ -1,24 +1,25 @@
 <template>
 	<div>
-		<uni-nav-bar :right-text="userName" title="棣栭〉" />
+		<uni-nav-bar
+			:right-text="userName"
+			title="棣栭〉"
+		/>
 	</div>
 </template>
 
 <script>
-	export default {
-		data() {
-			return {
-				userName: '123'
-			};
-		},
-		onLoad(obj) {
-			console.log(obj.name)
-			this.userName = uni.getStorageSync('userData')
-		},
-		methods: {}
-	}
+export default {
+	data() {
+		return {
+			userName: '123'
+		}
+	},
+	onLoad(obj) {
+		console.log(obj.name)
+		this.userName = uni.getStorageSync('userData')
+	},
+	methods: {}
+}
 </script>
 
-<style>
-
-</style>
\ No newline at end of file
+<style></style>
diff --git a/pages/login/api.js b/pages/login/api.js
new file mode 100644
index 0000000..7fe5bc1
--- /dev/null
+++ b/pages/login/api.js
@@ -0,0 +1,7 @@
+const http = uni.$u.http
+
+// 鐢ㄦ埛鐧诲綍
+export const login = (params) => http.get('/login.action', { params })
+
+// 杩欓噷鍙互缁х画娣诲姞鍏朵粬鎺ュ彛
+// export const getInfo = (data) => http.get('/user/info', data)
\ No newline at end of file
diff --git a/pages/login/index.nvue b/pages/login/index.nvue
new file mode 100644
index 0000000..01709d2
--- /dev/null
+++ b/pages/login/index.nvue
@@ -0,0 +1,559 @@
+<template>
+	<view class="bodyView">
+		<view>
+			<uni-nav-bar :fixed="true" :statusBar="true" :title="$t('page.login')" right-icon="gear" @clickRight="openSettings"></uni-nav-bar>
+		</view>
+		<!-- <image class="bgImage" src="/static/img/login_backg.png" mode="aspectFill"></image> -->
+		<view class="topView">
+			<image src="/static/img/login_top.png" mode="aspectFill">
+			</image>
+		</view>
+		<view class="logoView">
+			<image src="/static/img/newLogo.png" mode="aspectFit">
+			</image>
+		</view>
+		<view class="bottomView">
+			<view class="itemView" style="margin-bottom: 20px;">
+				<text class="helloText">{{$t('index.hello')}}</text>
+				<text class="introText">{{$t('index.intro')}}</text>
+			</view>
+			<view class="itemView">
+				<text class="textType3">{{$t('login.user')}}:</text>
+				<u-input clearable class="" v-model="user.userName" focus :placeholder="$t('login.inputUser')" />
+			</view>
+			<view class="itemView">
+				<text class="textType3">{{$t('login.pwd')}}:</text>
+
+				<u-input :password="showPassword" v-model="user.password" :placeholder="$t('login.inputPwd')"
+					suffixIcon="map-fill" suffixIconStyle="color: #909399">
+					<template slot="suffix">
+						<u-icon :name="pwdIcon" @click="changePassword"></u-icon>
+					</template>
+				</u-input>
+
+
+			</view>
+			<view class="langAndRemView">
+				<view class="check">
+					<view>
+						<text>{{$t('login.remPwd')}}</text>
+					</view>
+					<view>
+						<u-switch space="2" size="20" v-model="remberPassword" activeColor="#f9ae3d"
+							inactiveColor="rgb(230, 230, 230)">
+						</u-switch>
+						<!-- <switch :checked='remberPassword' color="#FFCC33" style="transform:scale(0.7)"
+							@change="remberChange" /> -->
+					</view>
+				</view>
+				<view class="langView">
+					<!-- 璇█閫夋嫨涓嬫媺鑿滃崟 -->
+					<view class="language-dropdown">
+						<view class="selected-language" @click="toggleLanguageDropdown">
+							<text>{{getCurrentLanguageText()}}</text>
+							<u-icon name="list" size="14" color="#707070"></u-icon>
+						</view>
+						<view class="language-options" v-if="showLanguageDropdown">
+							<view class="language-option" v-for="(item, index) in locales" :key="index"
+								@click="onLocaleChange(item)">
+								<text>{{item.text}}</text>
+								<u-icon name="checkbox-mark" color="#007AFF"
+									v-if="item.code == applicationLocale"></u-icon>
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+			<view class="itemView">
+				<u-button class="loadingButton" @click="onLogin()" :loading="loading">{{btnText}}</u-button>
+			</view>
+		</view>
+		<u-popup :show="showAuth" @close="showAuth = false" mode="center" :round="14" :customStyle="{width: '500rpx'}">
+			<view class="settings-popup">
+				<view class="settings-title">
+					<text class="settings-title-text">{{$t('settings.authTitle') || '韬唤楠岃瘉'}}</text>
+				</view>
+				<view class="settings-item">
+					<u-input v-model="authPassword" type="password" border="surround" :placeholder="$t('settings.inputAuthPwd') || '璇疯緭鍏ョ鐞嗗憳瀵嗙爜'" />
+				</view>
+				<view class="settings-buttons">
+					<u-button size="medium" @click="showAuth = false">{{$t('common.cancel') || '鍙栨秷'}}</u-button>
+					<view style="width: 20px;"></view>
+					<u-button size="medium" type="primary" @click="checkAuth">{{$t('common.confirm') || '纭'}}</u-button>
+				</view>
+			</view>
+		</u-popup>
+		<u-popup :show="showSettings" @close="showSettings = false" mode="center" :round="14" :closeOnClickOverlay="false" :customStyle="{width: '600rpx'}">
+			<view class="settings-popup">
+				<view class="settings-title">
+					<text class="settings-title-text">{{$t('settings.title') || '璁剧疆'}}</text>
+				</view>
+				<view class="settings-item">
+					<text class="settings-label">{{$t('settings.ip') || 'IP鍦板潃'}}:</text>
+					<u-input v-model="settings.ip" border="surround" />
+				</view>
+				<view class="settings-item">
+					<text class="settings-label">{{$t('settings.port') || '绔彛'}}:</text>
+					<u-input v-model="settings.port" border="surround" />
+				</view>
+				<view class="settings-item">
+					<text class="settings-label">{{$t('settings.project') || '椤圭洰鍚�'}}:</text>
+					<u-input v-model="settings.project" border="surround" />
+				</view>
+				<view class="settings-buttons">
+					<u-button size="medium" @click="showSettings = false">{{$t('common.cancel') || '鍙栨秷'}}</u-button>
+					<view style="width: 20px;"></view>
+					<u-button size="medium" type="primary" @click="saveSettings">{{$t('common.confirm') || '纭'}}</u-button>
+				</view>
+			</view>
+		</u-popup>
+		<u-toast ref="uToast"></u-toast>
+	</view>
+</template>
+
+<script>
+	import md5 from '../../static/js/md5.js'
+	import { login } from './api.js'
+
+	export default {
+		data() {
+			return {
+				showPassword: true,
+				loading: false,
+				showLanguageDropdown: false,
+				loginButton: 'login.login',
+				systemLocale: '',
+				applicationLocale: '',
+				remberPassword: true,
+				user: {
+					userName: '',
+					password: '',
+				},
+				passwordIcon: 'eye-off',
+				showSettings: false,
+				settings: {
+					ip: '',
+					port: '',
+					project: ''
+				},
+				showAuth: false,
+				authPassword: ''
+			}
+		},
+		computed: {
+			locales() {
+				return [{
+						text: this.$t('locale.auto'),
+						code: 'auto'
+					}, {
+						text: this.$t('locale.en'),
+						code: 'en'
+					},
+					{
+						text: this.$t('locale.zh-hans'),
+						code: 'zh-Hans'
+					},
+					{
+						text: this.$t('locale.zh-hant'),
+						code: 'zh-Hant'
+					},
+					{
+						text: this.$t('locale.ja'),
+						code: 'ja'
+					}
+				]
+			},
+			btnText() {
+				return this.$t(this.loginButton);
+			},
+			pwdIcon() {
+				return this.passwordIcon;
+			}
+		},
+		onLoad() {
+			let systemInfo = uni.getSystemInfoSync();
+			this.systemLocale = systemInfo.language;
+			this.applicationLocale = uni.getLocale();
+			this.isAndroid = systemInfo.platform.toLowerCase() === 'android';
+			uni.onLocaleChange((e) => {
+				this.applicationLocale = e.locale;
+			})
+
+			this.user = uni.getStorageSync('user')
+			if (!this.user) {
+				this.user = {
+					userName: '',
+					password: ''
+				}
+			}
+		},
+		methods: {
+			openSettings() {
+				this.showAuth = true;
+				this.authPassword = '';
+			},
+			checkAuth() {
+				// Default password: admin or 123456. Ideally from config.
+				if (this.authPassword === 'admin' || this.authPassword === '123456') {
+					this.showAuth = false;
+					this.loadSettings();
+				} else {
+					this.$refs.uToast.show({
+						type: 'error',
+						message: this.$t('settings.authError') || '瀵嗙爜閿欒',
+					});
+				}
+			},
+			loadSettings() {
+				this.showSettings = true;
+				let settings = uni.getStorageSync('app_settings');
+				if (!settings) {
+					settings = {
+						ip: '127.0.0.1',
+						port: '8080',
+						project: 'jshdasrs'
+					};
+				}
+				this.settings = settings;
+			},
+			saveSettings() {
+				uni.setStorageSync('app_settings', this.settings);
+				this.showSettings = false;
+				this.$refs.uToast.show({
+					type: 'success',
+					message: this.$t('settings.saved') || '璁剧疆宸蹭繚瀛�',
+				});
+			},
+						async onLogin() {
+							try {
+								const res = await login({
+									username: this.user.userName,
+									password: md5.hex_md5(this.user.password)
+								}, {
+									custom: {
+										catch: true
+									}
+								})
+			
+								this.loading = true;
+								this.loginButton = 'login.loging';
+								uni.setStorageSync('token', res.data.accessToken);
+								uni.setStorageSync('userData', res.data.username);
+								if (this.remberPassword) {
+									uni.setStorageSync('user', this.user);
+								} else {
+									uni.removeStorageSync('user');
+								}
+								this.goHome()
+							} catch (e) {
+								// 鎷︽埅鍣ㄥ凡澶勭悊 toast
+							}
+						},
+			goHome() {
+				setTimeout(() => {
+					this.$refs.uToast.show({
+						type: 'success',
+						message: "鐧诲綍鎴愬姛",
+						position: 'top'
+
+					});
+					setTimeout(() => {
+						uni.$u.route({
+							url: 'pages/index/index',
+							params: {
+								name: 'lisa'
+							}
+						})
+
+					}, 300)
+				}, 700)
+			},
+			remberChange(e) {
+				this.remberPassword = !this.remberPassword
+			},
+			// 鏄剧ず/闅愯棌瀵嗙爜
+			changePassword() {
+				this.passwordIcon = !this.showPassword ? 'eye-off' : 'eye'
+				this.showPassword = !this.showPassword;
+			},
+			localChange() {
+				console.log(this.local)
+				if (this.isAndroid) {
+					uni.showModal({
+						content: this.$t('index.language-change-confirm'),
+						success: (res) => {
+							if (res.confirm) {
+								uni.setLocale(this.local.value);
+							}
+						}
+					})
+				} else {
+					uni.setLocale(this.local.value);
+					this.$i18n.locale = this.local.value;
+				}
+			},
+			// 鍒囨崲璇█涓嬫媺鑿滃崟鏄剧ず鐘舵��
+			toggleLanguageDropdown() {
+				this.showLanguageDropdown = !this.showLanguageDropdown;
+			},
+
+			// 鑾峰彇褰撳墠閫夋嫨鐨勮瑷�鏂囨湰
+			getCurrentLanguageText() {
+				const currentLocale = this.locales.find(item => item.code === this.applicationLocale);
+				return currentLocale ? currentLocale.text : this.$t('locale.auto');
+			},
+
+			// 璇█閫夋嫨鏀瑰彉
+			onLocaleChange(e) {
+				if (this.isAndroid) {
+					uni.showModal({
+						content: this.$t('index.language-change-confirm'),
+						success: (res) => {
+							if (res.confirm) {
+								uni.setLocale(e.code);
+								this.showLanguageDropdown = false;
+							}
+						}
+					})
+				} else {
+					uni.setLocale(e.code);
+					this.$i18n.locale = e.code;
+					this.showLanguageDropdown = false;
+				}
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.helloText {
+		font-family: a2;
+		font-size: 20px;
+		margin-top: 10px;
+		margin-bottom: 5px;
+	}
+
+	.introText {
+		font-family: a3;
+		font-size: 15px;
+		color: #ababab;
+	}
+
+	.textType3 {
+		font-family: a4;
+	}
+
+	.bodyView {
+		flex: 1;
+		flex-direction: column;
+		width: 750rpx;
+	}
+
+	.bgImage {
+		position: fixed;
+		top: 0;
+		left: 0;
+		bottom: 0;
+		right: 0;
+	}
+
+	.topView {
+		flex: 7;
+	}
+
+	.topView image {
+		width: 100%;
+	}
+
+	.logoView {
+		flex: 1;
+		display: flex;
+		justify-content: flex-end;
+		align-items: flex-end;
+
+	}
+
+	.logoView image {
+		width: 33%;
+		height: 50px;
+		margin-right: 20px;
+	}
+
+	.bottomView {
+		flex: 15;
+		display: flex;
+		flex-direction: column;
+		justify-content: flex-start;
+		align-items: center;
+	}
+
+	.itemView {
+		width: 90%;
+		margin-bottom: 5px;
+	}
+
+	.langAndRemView {
+		width: 90%;
+		display: flex;
+		flex-direction: row;
+		justify-content: space-between;
+		align-items: center;
+		margin-bottom: 5px;
+	}
+
+	.langView {
+		width: 30%;
+	}
+
+	.textImage {
+		width: 60%;
+		height: 42px;
+		object-fit: cover;
+		margin-top: 20px;
+		margin-bottom: 30px;
+	}
+
+	.input-wrapper {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		padding: 8px 13px;
+		flex-direction: row;
+		flex-wrap: nowrap;
+		background-color: #FFFFFF;
+		border-radius: 10px;
+		height: 45px;
+		align-items: center;
+		margin-top: 5px;
+	}
+
+	.uni-input {
+		height: 28px;
+		line-height: 28px;
+		font-size: 15px;
+		padding: 0px;
+		flex: 1;
+		background-color: #FFFFFF;
+
+	}
+
+	.uni-icon {
+		font-family: uniicons;
+		font-size: 24px;
+		font-weight: normal;
+		font-style: normal;
+		width: 24px;
+		height: 24px;
+		line-height: 24px;
+		color: #999999;
+	}
+
+	.uni-eye-active {
+		color: #007AFF;
+	}
+
+	.eye-icon {
+		width: 20px;
+		height: 13px;
+		margin-left: 5px;
+	}
+
+	.loadingButton {
+		background-color: #ffda1e;
+		font-family: a1;
+	}
+
+	.check {
+
+		height: 100%;
+		display: flex;
+		flex-direction: row;
+		font-size: 18px;
+		color: #606266;
+		justify-content: flex-start;
+		align-items: center;
+
+	}
+
+	/* 璇█閫夋嫨涓嬫媺鑿滃崟 */
+	.language-dropdown {
+		position: relative;
+		margin-bottom: 20rpx;
+		z-index: 10;
+	}
+
+	.selected-language {
+		display: flex;
+		flex-direction: row;
+		justify-content: space-between;
+		align-items: center;
+		padding: 15rpx 20rpx;
+		background-color: #f8f8f8;
+		border-radius: 8rpx;
+		border: 1px solid #e0e0e0;
+	}
+
+	.language-options {
+		position: absolute;
+		bottom: 100%;
+		left: 0;
+		right: 0;
+		background-color: #ffffff;
+		border-radius: 8rpx;
+		box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+		border: 1px solid #e0e0e0;
+		margin-bottom: 5rpx;
+	}
+
+	.language-option {
+		display: flex;
+		flex-direction: row;
+		justify-content: space-between;
+		align-items: center;
+		padding: 15rpx 20rpx;
+		border-bottom: 1px solid #f0f0f0;
+	}
+
+	.language-option:last-child {
+		border-bottom: none;
+	}
+
+	.language-option:active {
+		background-color: #f5f5f5;
+	}
+
+	.settings-popup {
+		padding: 20px;
+		background-color: #ffffff;
+		border-radius: 10px;
+		display: flex;
+		flex-direction: column;
+	}
+
+	.settings-title {
+		margin-bottom: 20px;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.settings-title-text {
+		font-size: 18px;
+		font-weight: bold;
+	}
+
+	.settings-item {
+		margin-bottom: 15px;
+	}
+
+	.settings-label {
+		margin-bottom: 5px;
+		font-size: 14px;
+		color: #606266;
+	}
+
+	.settings-buttons {
+		flex-direction: row;
+		justify-content: center;
+		margin-top: 10px;
+	}
+</style>
\ No newline at end of file
diff --git a/pages/login/login.vue b/pages/login/login.vue
index a0d860e..f015b1e 100644
--- a/pages/login/login.vue
+++ b/pages/login/login.vue
@@ -1,437 +1,673 @@
 <template>
 	<view class="bodyView">
+		<view>
+			<u-navbar
+				:fixed="true"
+				:title="$t('page.login')"
+				rightIcon="setting"
+				left-icon=""
+				:placeholder="true"
+				@rightClick="openSettings"
+			></u-navbar>
+		</view>
 		<view class="topView">
-			<image src="/static/img/login_top.png" mode="aspectFill">
-			</image>
+			<u--image
+				width="100%"
+				src="/static/img/login_top.png"
+				mode="aspectFill"
+			></u--image>
 		</view>
 		<view class="logoView">
-			<image src="/static/img/newLogo.png" mode="aspectFit">
-			</image>
+			<image
+				src="/static/img/newLogo.png"
+				mode="aspectFit"
+			></image>
 		</view>
 		<view class="bottomView">
-			<view class="itemView" style="margin-bottom: 40px;">
-				<view class="helloText">{{$t('index.hello')}}</view>
-				<view class="introText">{{$t('index.intro')}}</view>
+			<view
+				class="itemView"
+				style="margin-bottom: 20px"
+			>
+				<view class="helloText">{{ $t('index.hello') }}</view>
+				<view class="introText">{{ $t('index.intro') }}</view>
 			</view>
 			<view class="itemView">
-				<view class="textType3">{{$t('login.user')}}:</view>
-				<u-input clearable class="" v-model="user.userName" focus :placeholder="$t('login.inputUser')" />
+				<text class="textType3">{{ $t('login.user') }}:</text>
+				<u-input
+					clearable
+					class=""
+					v-model="user.userName"
+					focus
+					:placeholder="$t('login.inputUser')"
+				/>
 			</view>
 			<view class="itemView">
-				<view class="textType3">{{$t('login.pwd')}}:</view>
+				<text class="textType3">{{ $t('login.pwd') }}:</text>
 
-				<u-input :password="showPassword" v-model="user.password" :placeholder="$t('login.inputPwd')"
-					suffixIcon="map-fill" suffixIconStyle="color: #909399">
+				<u-input
+					:password="showPassword"
+					v-model="user.password"
+					:placeholder="$t('login.inputPwd')"
+					suffixIcon="map-fill"
+					suffixIconStyle="color: #909399"
+				>
 					<template slot="suffix">
-						<u-icon :name="pwdIcon" @click="changePassword"></u-icon>
+						<u-icon
+							:name="pwdIcon"
+							@click="changePassword"
+						></u-icon>
 					</template>
 				</u-input>
-
-
 			</view>
 			<view class="langAndRemView">
 				<view class="check">
 					<view>
-						<view>{{$t('login.remPwd')}}</view>
+						<text>{{ $t('login.remPwd') }}</text>
 					</view>
 					<view>
-						<u-switch space="2" size="20" v-model="remberPassword" activeColor="#f9ae3d"
-							inactiveColor="rgb(230, 230, 230)">
-						</u-switch>
-						<!-- <switch :checked='remberPassword' color="#FFCC33" style="transform:scale(0.7)"
-							@change="remberChange" /> -->
+						<u-switch
+							space="2"
+							size="20"
+							v-model="remberPassword"
+							activeColor="#f9ae3d"
+							inactiveColor="rgb(230, 230, 230)"
+						></u-switch>
 					</view>
 				</view>
 				<view class="langView">
 					<!-- 璇█閫夋嫨涓嬫媺鑿滃崟 -->
 					<view class="language-dropdown">
-						<view class="selected-language" @click="toggleLanguageDropdown">
-							<text>{{getCurrentLanguageText()}}</text>
-							<u-icon name="list" size="14" color="#707070"></u-icon>
+						<view
+							class="selected-language"
+							@click="toggleLanguageDropdown"
+						>
+							<text>{{ getCurrentLanguageText() }}</text>
+							<u-icon
+								name="list"
+								size="14"
+								color="#707070"
+							></u-icon>
 						</view>
-						<view class="language-options" v-if="showLanguageDropdown">
-							<view class="language-option" v-for="(item, index) in locales" :key="index"
-								@click="onLocaleChange(item)">
-								<text>{{item.text}}</text>
-								<u-icon name="checkbox-mark" color="#007AFF"
-									v-if="item.code == applicationLocale"></u-icon>
+						<view
+							class="language-options"
+							v-if="showLanguageDropdown"
+						>
+							<view
+								class="language-option"
+								v-for="(item, index) in locales"
+								:key="index"
+								@click="onLocaleChange(item)"
+							>
+								<text>{{ item.text }}</text>
+								<u-icon
+									name="checkbox-mark"
+									color="#007AFF"
+									v-if="item.code == applicationLocale"
+								></u-icon>
 							</view>
 						</view>
 					</view>
 				</view>
 			</view>
 			<view class="itemView">
-				<u-button class="loadingButton" @click="onLogin()" :loading="loading">{{btnText}}</u-button>
+				<u-button
+					class="loadingButton"
+					@click="onLogin()"
+					:loading="loading"
+				>
+					{{ btnText }}
+				</u-button>
 			</view>
 		</view>
+		<u-popup
+			:show="showAuth"
+			@close="showAuth = false"
+			mode="center"
+			:round="14"
+			:customStyle="{ width: '500rpx' }"
+		>
+			<view class="settings-popup">
+				<view class="settings-title">
+					<text class="settings-title-text">
+						{{ $t('settings.authTitle') || '韬唤楠岃瘉' }}
+					</text>
+				</view>
+				<view class="settings-item">
+					<u-input
+						v-model="authPassword"
+						type="password"
+						border="surround"
+						:placeholder="
+							$t('settings.inputAuthPwd') || '璇疯緭鍏ョ鐞嗗憳瀵嗙爜'
+						"
+					/>
+				</view>
+				<view class="settings-buttons">
+					<u-button
+						size="medium"
+						@click="showAuth = false"
+					>
+						{{ $t('common.cancel') || '鍙栨秷' }}
+					</u-button>
+					<view style="width: 20px"></view>
+					<u-button
+						size="medium"
+						type="primary"
+						@click="checkAuth"
+					>
+						{{ $t('common.confirm') || '纭' }}
+					</u-button>
+				</view>
+			</view>
+		</u-popup>
+		<u-popup
+			:show="showSettings"
+			@close="showSettings = false"
+			mode="center"
+			:round="14"
+			:closeOnClickOverlay="false"
+			:customStyle="{ width: '600rpx' }"
+		>
+			<view class="settings-popup">
+				<view class="settings-title">
+					<text class="settings-title-text">
+						{{ $t('settings.title') || '璁剧疆' }}
+					</text>
+				</view>
+				<view class="settings-item">
+					<text class="settings-label">
+						{{ $t('settings.ip') || 'IP鍦板潃' }}:
+					</text>
+					<u-input
+						v-model="settings.ip"
+						border="surround"
+					/>
+				</view>
+				<view class="settings-item">
+					<text class="settings-label">
+						{{ $t('settings.port') || '绔彛' }}:
+					</text>
+					<u-input
+						v-model="settings.port"
+						border="surround"
+					/>
+				</view>
+				<view class="settings-item">
+					<text class="settings-label">
+						{{ $t('settings.project') || '椤圭洰鍚�' }}:
+					</text>
+					<u-input
+						v-model="settings.project"
+						border="surround"
+					/>
+				</view>
+				<view class="settings-buttons">
+					<u-button
+						size="medium"
+						@click="showSettings = false"
+					>
+						{{ $t('common.cancel') || '鍙栨秷' }}
+					</u-button>
+					<view style="width: 20px"></view>
+					<u-button
+						size="medium"
+						type="primary"
+						@click="saveSettings"
+					>
+						{{ $t('common.confirm') || '纭' }}
+					</u-button>
+				</view>
+			</view>
+		</u-popup>
 		<u-toast ref="uToast"></u-toast>
 	</view>
 </template>
 
 <script>
-	import md5 from '../../static/js/md5.js'
-	import {
-		request
-	} from '../../common/request.js'
-	export default {
-		data() {
-			return {
-				showPassword: true,
-				loading: false,
-				showLanguageDropdown: false,
-				loginButton: 'login.login',
-				systemLocale: '',
-				applicationLocale: '',
-				remberPassword: true,
-				user: {
-					userName: '',
-					password: '',
+import md5 from '../../static/js/md5.js'
+import { login } from './api.js'
+export default {
+	data() {
+		return {
+			showPassword: true,
+			loading: false,
+			showLanguageDropdown: false,
+			loginButton: 'login.login',
+			systemLocale: '',
+			applicationLocale: '',
+			remberPassword: true,
+			user: {
+				userName: '',
+				password: ''
+			},
+			passwordIcon: 'eye-off',
+			showSettings: false,
+			settings: {
+				ip: '',
+				port: '',
+				project: ''
+			},
+			showAuth: false,
+			authPassword: ''
+		}
+	},
+	computed: {
+		locales() {
+			return [
+				{
+					text: this.$t('locale.auto'),
+					code: 'auto'
 				},
-				passwordIcon: 'eye-off'
+				{
+					text: this.$t('locale.en'),
+					code: 'en'
+				},
+				{
+					text: this.$t('locale.zh-hans'),
+					code: 'zh-Hans'
+				},
+				{
+					text: this.$t('locale.zh-hant'),
+					code: 'zh-Hant'
+				},
+				{
+					text: this.$t('locale.ja'),
+					code: 'ja'
+				}
+			]
+		},
+		btnText() {
+			return this.$t(this.loginButton)
+		},
+		pwdIcon() {
+			return this.passwordIcon
+		}
+	},
+	onLoad() {
+		let systemInfo = uni.getSystemInfoSync()
+		this.systemLocale = systemInfo.language
+		this.applicationLocale = uni.getLocale()
+		this.isAndroid = systemInfo.platform.toLowerCase() === 'android'
+		uni.onLocaleChange((e) => {
+			this.applicationLocale = e.locale
+		})
+
+		this.user = uni.getStorageSync('user')
+		if (!this.user) {
+			this.user = {
+				userName: '',
+				password: ''
+			}
+		}
+	},
+	methods: {
+		openSettings() {
+			this.showAuth = true
+			this.authPassword = ''
+		},
+		checkAuth() {
+			// Default password: admin or 123456. Ideally from config.
+			if (
+				this.authPassword === 'admin' ||
+				this.authPassword === '123456'
+			) {
+				this.showAuth = false
+				this.loadSettings()
+			} else {
+				this.$refs.uToast.show({
+					type: 'error',
+					message: this.$t('settings.authError') || '瀵嗙爜閿欒'
+				})
 			}
 		},
-		computed: {
-			locales() {
-				return [{
-						text: this.$t('locale.auto'),
-						code: 'auto'
-					}, {
-						text: this.$t('locale.en'),
-						code: 'en'
-					},
-					{
-						text: this.$t('locale.zh-hans'),
-						code: 'zh-Hans'
-					},
-					{
-						text: this.$t('locale.zh-hant'),
-						code: 'zh-Hant'
-					},
-					{
-						text: this.$t('locale.ja'),
-						code: 'ja'
-					}
-				]
-			},
-			btnText() {
-				return this.$t(this.loginButton);
-			},
-			pwdIcon() {
-				return this.passwordIcon;
+		loadSettings() {
+			this.showSettings = true
+			let settings = uni.getStorageSync('app_settings')
+			if (!settings) {
+				settings = {
+					ip: '127.0.0.1',
+					port: '8080',
+					project: 'jshdasrs'
+				}
 			}
+			this.settings = settings
 		},
-		onLoad() {
-			let systemInfo = uni.getSystemInfoSync();
-			this.systemLocale = systemInfo.language;
-			this.applicationLocale = uni.getLocale();
-			this.isAndroid = systemInfo.platform.toLowerCase() === 'android';
-			uni.onLocaleChange((e) => {
-				this.applicationLocale = e.locale;
+		saveSettings() {
+			uni.setStorageSync('app_settings', this.settings)
+			console.log(this.settings)
+			this.showSettings = false
+			this.$refs.uToast.show({
+				type: 'success',
+				message: this.$t('settings.saved') || '璁剧疆宸蹭繚瀛�'
 			})
+		},
+		async onLogin() {
+			try {
+				const res = await login(
+					{
+						username: this.user.userName,
+						password: md5.hex_md5(this.user.password)
+					},
+					{ custom: { catch: true } }
+				)
 
-			this.user = uni.getStorageSync('user')
-			if (!this.user) {
-				this.user = {
-					userName: '',
-					password: ''
+				this.loading = true
+				this.loginButton = 'login.loging'
+				uni.setStorageSync('token', res.data.accessToken)
+				uni.setStorageSync('userData', res.data.username)
+				if (this.remberPassword) {
+					uni.setStorageSync('user', this.user)
+				} else {
+					uni.removeStorageSync('user')
 				}
+				this.goHome()
+			} catch (e) {
+				// 鎷︽埅鍣ㄥ凡澶勭悊 toast
 			}
 		},
-		methods: {
-			async onLogin() {
-				const {
-					code,
-					data,
-					msg
-				} = await request('/login.action', {
-					username: this.user.userName,
-					password: md5.hex_md5(this.user.password),
-
-				}, 'GET')
-				if (code === 200) {
-					this.loading = true;
-					this.loginButton = 'login.loging';
-					uni.setStorageSync('token', data.accessToken);
-					uni.setStorageSync('userData', data.username);
-					if (this.remberPassword) {
-						uni.setStorageSync('user', this.user);
-					} else {
-						uni.removeStorageSync('user');
-					}
-					this.goHome()
-				} else {
-					this.$refs.uToast.show({
-						type: 'error',
-						message: "璇锋鏌ユ帴鍙h繛鎺�",
-						position: 'top'
-
-					});
-				}
-
-			},
-			goHome() {
+		goHome() {
+			setTimeout(() => {
+				this.$refs.uToast.show({
+					type: 'success',
+					message: '鐧诲綍鎴愬姛',
+					position: 'top'
+				})
 				setTimeout(() => {
-					this.$refs.uToast.show({
-						type: 'success',
-						message: "鐧诲綍鎴愬姛",
-						position: 'top'
-
-					});
-					setTimeout(() => {
-						uni.$u.route({
-							url: 'pages/index/index',
-							params: {
-								name: 'lisa'
-							}
-						})
-
-					}, 300)
-				}, 700)
-			},
-			remberChange(e) {
-				this.remberPassword = !this.remberPassword
-			},
-			// 鏄剧ず/闅愯棌瀵嗙爜
-			changePassword() {
-				this.passwordIcon = !this.showPassword ? 'eye-off' : 'eye'
-				this.showPassword = !this.showPassword;
-			},
-			localChange() {
-				console.log(this.local)
-				if (this.isAndroid) {
-					uni.showModal({
-						content: this.$t('index.language-change-confirm'),
-						success: (res) => {
-							if (res.confirm) {
-								uni.setLocale(this.local.value);
-							}
+					uni.$u.route({
+						type: 'reLaunch',
+						url: 'pages/home/home',
+						params: {
+							name: 'lisa'
 						}
 					})
-				} else {
-					uni.setLocale(this.local.value);
-					this.$i18n.locale = this.local.value;
-				}
-			},
-			// 鍒囨崲璇█涓嬫媺鑿滃崟鏄剧ず鐘舵��
-			toggleLanguageDropdown() {
-				this.showLanguageDropdown = !this.showLanguageDropdown;
-			},
-
-			// 鑾峰彇褰撳墠閫夋嫨鐨勮瑷�鏂囨湰
-			getCurrentLanguageText() {
-				const currentLocale = this.locales.find(item => item.code === this.applicationLocale);
-				return currentLocale ? currentLocale.text : this.$t('locale.auto');
-			},
-
-			// 璇█閫夋嫨鏀瑰彉
-			onLocaleChange(e) {
-				if (this.isAndroid) {
-					uni.showModal({
-						content: this.$t('index.language-change-confirm'),
-						success: (res) => {
-							if (res.confirm) {
-								uni.setLocale(e.code);
-								this.showLanguageDropdown = false;
-							}
+				}, 300)
+			}, 700)
+		},
+		remberChange(e) {
+			this.remberPassword = !this.remberPassword
+		},
+		// 鏄剧ず/闅愯棌瀵嗙爜
+		changePassword() {
+			this.passwordIcon = !this.showPassword ? 'eye-off' : 'eye'
+			this.showPassword = !this.showPassword
+		},
+		localChange() {
+			console.log(this.local)
+			if (this.isAndroid) {
+				uni.showModal({
+					content: this.$t('index.language-change-confirm'),
+					success: (res) => {
+						if (res.confirm) {
+							uni.setLocale(this.local.value)
 						}
-					})
-				} else {
-					uni.setLocale(e.code);
-					this.$i18n.locale = e.code;
-					this.showLanguageDropdown = false;
-				}
-			},
+					}
+				})
+			} else {
+				uni.setLocale(this.local.value)
+				this.$i18n.locale = this.local.value
+			}
+		},
+		// 鍒囨崲璇█涓嬫媺鑿滃崟鏄剧ず鐘舵��
+		toggleLanguageDropdown() {
+			this.showLanguageDropdown = !this.showLanguageDropdown
+		},
+
+		// 鑾峰彇褰撳墠閫夋嫨鐨勮瑷�鏂囨湰
+		getCurrentLanguageText() {
+			const currentLocale = this.locales.find(
+				(item) => item.code === this.applicationLocale
+			)
+			return currentLocale ? currentLocale.text : this.$t('locale.auto')
+		},
+
+		// 璇█閫夋嫨鏀瑰彉
+		onLocaleChange(e) {
+			if (this.isAndroid) {
+				uni.showModal({
+					content: this.$t('index.language-change-confirm'),
+					success: (res) => {
+						if (res.confirm) {
+							uni.setLocale(e.code)
+							this.showLanguageDropdown = false
+						}
+					}
+				})
+			} else {
+				uni.setLocale(e.code)
+				this.$i18n.locale = e.code
+				this.showLanguageDropdown = false
+			}
 		}
 	}
+}
 </script>
 
 <style lang="scss" scoped>
-	.helloText {
-		font-family: a2;
-		font-size: 20px;
-		margin-top: 10px;
-		margin-bottom: 5px;
-	}
+.helloText {
+	font-family: a2;
+	font-size: 20px;
+	margin-top: 10px;
+	margin-bottom: 5px;
+}
 
-	.introText {
-		font-family: a3;
-		font-size: 15px;
-		color: #ababab;
-	}
+.introText {
+	font-family: a3;
+	font-size: 15px;
+	color: #ababab;
+}
 
-	.textType3 {
-		font-family: a4;
-	}
+.textType3 {
+	font-family: a4;
+}
 
-	.bodyView {
-		display: flex;
-		flex-direction: column;
-		background-image: url("/static/img/login_backg.png");
-		background-repeat: no-repeat;
-		background-size: cover;
-		background-position: center;
-		height: 100vh;
-		width: 100%;
-	}
+.bodyView {
+	flex: 1;
+	flex-direction: column;
+	width: 750rpx;
+}
 
-	.topView {
-		flex: 7;
-	}
+.bgImage {
+	position: fixed;
+	top: 0;
+	left: 0;
+	bottom: 0;
+	right: 0;
+}
 
-	.topView image {
-		width: 100%;
-	}
+.topView {
+	flex: 7;
+}
 
-	.logoView {
-		flex: 1;
-		display: flex;
-		justify-content: flex-end;
-		align-items: center;
+.topView image {
+	width: 100%;
+}
 
-	}
+.logoView {
+	flex: 1;
+	display: flex;
+	justify-content: flex-end;
+	align-items: flex-end;
+}
 
-	.logoView image {
-		width: 33%;
-		height: 50px;
-		margin-right: 20px;
-	}
+.logoView image {
+	width: 33%;
+	height: 50px;
+	margin-right: 20px;
+}
 
-	.bottomView {
-		flex: 15;
-		display: flex;
-		flex-direction: column;
-		justify-content: flex-start;
-		align-items: center;
-	}
+.bottomView {
+	flex: 15;
+	display: flex;
+	flex-direction: column;
+	justify-content: flex-start;
+	align-items: center;
+}
 
-	.itemView {
-		width: 90%;
-		height: 50px;
-		margin-bottom: 30px;
-	}
+.itemView {
+	width: 90%;
+	margin-bottom: 5px;
+}
 
-	.langAndRemView {
-		width: 90%;
-		display: flex;
-		justify-content: space-between;
-		align-items: center;
-	}
+.langAndRemView {
+	width: 90%;
+	display: flex;
+	flex-direction: row;
+	justify-content: space-between;
+	align-items: center;
+	margin-bottom: 5px;
+}
 
-	.langView {
-		width: 30%;
-	}
+.langView {
+	width: 30%;
+}
 
-	.textImage {
-		width: 60%;
-		height: 42px;
-		object-fit: cover;
-		margin-top: 20px;
-		margin-bottom: 30px;
-	}
+.textImage {
+	width: 60%;
+	height: 42px;
+	object-fit: cover;
+	margin-top: 20px;
+	margin-bottom: 30px;
+}
 
-	.input-wrapper {
-		/* #ifndef APP-NVUE */
-		display: flex;
-		/* #endif */
-		padding: 8px 13px;
-		flex-direction: row;
-		flex-wrap: nowrap;
-		background-color: #FFFFFF;
-		border-radius: 10px;
-		height: 45px;
-		align-items: center;
-		margin-top: 5px;
-	}
+.input-wrapper {
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	padding: 8px 13px;
+	flex-direction: row;
+	flex-wrap: nowrap;
+	background-color: #ffffff;
+	border-radius: 10px;
+	height: 45px;
+	align-items: center;
+	margin-top: 5px;
+}
 
-	.uni-input {
-		height: 28px;
-		line-height: 28px;
-		font-size: 15px;
-		padding: 0px;
-		flex: 1;
-		background-color: #FFFFFF;
+.uni-input {
+	height: 28px;
+	line-height: 28px;
+	font-size: 15px;
+	padding: 0px;
+	flex: 1;
+	background-color: #ffffff;
+}
 
-	}
+.uni-icon {
+	font-family: uniicons;
+	font-size: 24px;
+	font-weight: normal;
+	font-style: normal;
+	width: 24px;
+	height: 24px;
+	line-height: 24px;
+	color: #999999;
+}
 
-	.uni-icon {
-		font-family: uniicons;
-		font-size: 24px;
-		font-weight: normal;
-		font-style: normal;
-		width: 24px;
-		height: 24px;
-		line-height: 24px;
-		color: #999999;
-	}
+.uni-eye-active {
+	color: #007aff;
+}
 
-	.uni-eye-active {
-		color: #007AFF;
-	}
+.eye-icon {
+	width: 20px;
+	height: 13px;
+	margin-left: 5px;
+}
 
-	.eye-icon {
-		width: 20px;
-		height: 13px;
-		margin-left: 5px;
-	}
+.loadingButton {
+	background-color: #ffda1e;
+	font-family: a1;
+}
 
-	.loadingButton {
-		background-color: #ffda1e;
-		font-family: a1;
-	}
+.check {
+	height: 100%;
+	display: flex;
+	flex-direction: row;
+	font-size: 18px;
+	color: #606266;
+	justify-content: flex-start;
+	align-items: center;
+}
 
-	.check {
+/* 璇█閫夋嫨涓嬫媺鑿滃崟 */
+.language-dropdown {
+	position: relative;
+	margin-bottom: 20rpx;
+	z-index: 10;
+}
 
-		height: 100%;
-		display: flex;
-		font-size: 18px;
-		color: #606266;
-		justify-content: flex-start;
-		align-items: center;
+.selected-language {
+	display: flex;
+	flex-direction: row;
+	justify-content: space-between;
+	align-items: center;
+	padding: 15rpx 20rpx;
+	background-color: #f8f8f8;
+	border-radius: 8rpx;
+	border: 1px solid #e0e0e0;
+}
 
-	}
+.language-options {
+	position: absolute;
+	bottom: 100%;
+	left: 0;
+	right: 0;
+	background-color: #ffffff;
+	border-radius: 8rpx;
+	box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+	border: 1px solid #e0e0e0;
+	margin-bottom: 5rpx;
+}
 
-	/* 璇█閫夋嫨涓嬫媺鑿滃崟 */
-	.language-dropdown {
-		position: relative;
-		margin-bottom: 20rpx;
-		z-index: 10;
-	}
+.language-option {
+	display: flex;
+	flex-direction: row;
+	justify-content: space-between;
+	align-items: center;
+	padding: 15rpx 20rpx;
+	border-bottom: 1px solid #f0f0f0;
+}
 
-	.selected-language {
-		display: flex;
-		justify-content: space-between;
-		align-items: center;
-		padding: 15rpx 20rpx;
-		background-color: #f8f8f8;
-		border-radius: 8rpx;
-		border: 1px solid #e0e0e0;
-	}
+.language-option:last-child {
+	border-bottom: none;
+}
 
-	.language-options {
-		position: absolute;
-		bottom: 100%;
-		left: 0;
-		right: 0;
-		background-color: #ffffff;
-		border-radius: 8rpx;
-		box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
-		border: 1px solid #e0e0e0;
-		margin-bottom: 5rpx;
-	}
+.language-option:active {
+	background-color: #f5f5f5;
+}
 
-	.language-option {
-		display: flex;
-		justify-content: space-between;
-		align-items: center;
-		padding: 15rpx 20rpx;
-		border-bottom: 1px solid #f0f0f0;
-	}
+.settings-popup {
+	padding: 20px;
+	background-color: #ffffff;
+	border-radius: 10px;
+	display: flex;
+	flex-direction: column;
+}
 
-	.language-option:last-child {
-		border-bottom: none;
-	}
+.settings-title {
+	margin-bottom: 20px;
+	align-items: center;
+	justify-content: center;
+}
 
-	.language-option:active {
-		background-color: #f5f5f5;
-	}
-</style>
\ No newline at end of file
+.settings-title-text {
+	font-size: 18px;
+	font-weight: bold;
+}
+
+.settings-item {
+	margin-bottom: 15px;
+}
+
+.settings-label {
+	margin-bottom: 5px;
+	font-size: 14px;
+	color: #606266;
+}
+
+.settings-buttons {
+	display: flex;
+	flex-direction: row;
+	justify-content: center;
+	margin-top: 10px;
+}
+</style>

--
Gitblit v1.9.1