diff --git a/.workbuddy/expert-history.json b/.workbuddy/expert-history.json
index 81ad213..7e54581 100644
--- a/.workbuddy/expert-history.json
+++ b/.workbuddy/expert-history.json
@@ -1,17 +1,26 @@
{
"version": 2,
"sessions": {
- "81d18d7cb0a14f7b80ab19186392c337": [
+ "9da290b417a44c7b9720d6545f2e14d7": [
+ {
+ "expertId": "FrontendDeveloper",
+ "name": "Paul",
+ "profession": "前端开发工程师",
+ "avatarUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/avatars/02-Engineering/FrontendDeveloper/FrontendDeveloper.png",
+ "promptUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/experts/02-Engineering/FrontendDeveloper/FrontendDeveloper_zh.md",
+ "usedAt": 1776167527349,
+ "industryId": "all"
+ },
{
"expertId": "BackendArchitect",
"name": "Joy",
"profession": "后端架构师",
"avatarUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/avatars/02-Engineering/BackendArchitect/BackendArchitect.png",
"promptUrl": "https://acc-1258344699.cos.accelerate.myqcloud.com/workbuddy/experts/experts/02-Engineering/BackendArchitect/BackendArchitect_zh.md",
- "usedAt": 1776079998628,
+ "usedAt": 1776163421500,
"industryId": "all"
}
]
},
- "lastUpdated": 1776160119257
+ "lastUpdated": 1776167527349
}
\ No newline at end of file
diff --git a/.workbuddy/memory/2026-04-13.md b/.workbuddy/memory/2026-04-13.md
deleted file mode 100644
index 6b70c93..0000000
--- a/.workbuddy/memory/2026-04-13.md
+++ /dev/null
@@ -1,32 +0,0 @@
-# 2026-04-13
-
-## ops2 项目采购模块改造
-
-为采购订单增加状态管理功能,涉及前后端多处改动:
-
-### 后端改动
-- `TabPurchaseOrder` 新增 `OrderStatus` 字段(pending/ordered/arrived/received),默认 pending
-- `TabPurchaseOrder` 新增 `UpdatedAt` 字段(GORM autoUpdateTime)
-- `TabPurchaseCosts` 新增 `CurrencyType`(1-CNY 2-MOP 3-HKD 4-USD)和 `CostType`(1-单价 2-运费)
-- 新表 `TabPurchaseCommit`:记录每次状态变更(Action: create/create_status)、旧状态、新状态、评论、操作IP
-- `CostItem` 前端结构体 `CurrencyType` 和 `Type` 从 string 改为 int(与数据库一致)
-- `/purchase/getorder` 新增返回 `commits`(状态变更记录列表)
-- `/purchase/updatestatus` 新接口:更新订单状态,可选附带 comment,写入 TabPurchaseCommit + TabPurchaseLog
-- `addorder` 创建时自动写入第一条 commit(状态 pending)
-- 状态值白名单校验:只允许 pending/ordered/arrived/received
-
-### 前端改动
-- `api/purchase.js` 新增 `updateOrderStatus(id, status, comment)` 方法
-- `PurchaseList.vue` 列表页去掉假数据列,显示真实标题/备注/创建时间,状态用彩色标签(黄-待处理、蓝-已下单、紫-已到达、绿-已收件)
-- `ShowOrder.vue` 详情页新增:状态快捷切换按钮(四个状态一键切换)、状态变更 commit 历史时间线(竖排列表,含状态标签+时间+评论)
-- i18n 同步新增 8 个翻译 key
-
-### 新增:状态变更弹窗(含备注输入)
-- `ShowOrder.vue` 中状态按钮不再直接变更,改为弹出确认框
-- 弹窗包含:目标状态标签 + 备注 textarea(支持 Ctrl+Enter 快捷确认)
-- 备注内容通过 `updateOrderStatus(id, status, comment)` 提交
-- `message.save_success` 已补充到中英 i18n 文件
-
-### 注意事项
-- 重启后端后 GORM AutoMigrate 会自动新增字段和表,无需手动 SQL
-- 前端 `CostItem` 的 CurrencyType/Type 改为 int,与后端一致
diff --git a/.workbuddy/memory/2026-04-14.md b/.workbuddy/memory/2026-04-14.md
index 9d14c43..f66c7f9 100644
--- a/.workbuddy/memory/2026-04-14.md
+++ b/.workbuddy/memory/2026-04-14.md
@@ -1,6 +1,36 @@
-# 2026-04-14 工作记录
+# 2026-04-14 工作日志
-## showorder.vue 编辑权限控制
+## 今日完成
-- 后端 `/getorder` 接口返回 `canModify` 字段,由 `canModifyPurchase(user.ID, order.UserID)` 判断
-- 前端 showorder.vue 编辑按钮条件改为 `v-if="canModify"`
+### uni-app 移动端开发
+
+#### 基础架构
+- 创建 `pages/login/login.vue` - 登录页面(组合式 API + vue-i18n)
+- 创建 `pages/register/register.vue` - 注册页面
+- 创建 `pages/index/index.vue` - 首页(订单统计、快捷操作)
+- 创建 `pages/settings/apiConfig.vue` - API 配置页面
+- 更新 `pages.json` - 添加 tabBar 配置
+- 更新 `main.js` - 支持本地存储覆盖 API(默认 http://192.168.13.105/api/)
+- 更新 `App.vue` - 初始化全局 API 地址
+- 创建 `static/tabbar/` - 底部导航图标(home/settings)
+
+#### i18n 国际化
+- 创建 `locales/zh.js` / `locales/en.js` - 中英文语言包
+- 切换到 vue-i18n(组合式 API)
+- 支持中英文切换(中文/EN)
+
+#### 技术栈
+- uni-app + Vue3 Composition API
+- vue-i18n 国际化
+- 组合式 API (
diff --git a/frontend/ops_uniapp/locales/en.js b/frontend/ops_uniapp/locales/en.js
new file mode 100644
index 0000000..b30284c
--- /dev/null
+++ b/frontend/ops_uniapp/locales/en.js
@@ -0,0 +1,111 @@
+export default {
+ // tabBar
+ tabBar: {
+ home: 'Home',
+ settings: 'Settings',
+ },
+ // 首页
+ index: {
+ welcome: 'Welcome to OPS',
+ subtitle: 'Operations Management System',
+ quickActions: 'Quick Actions',
+ allOrders: 'All Orders',
+ addOrder: 'New Order',
+ schedule: 'Schedule',
+ language: 'Language',
+ logout: 'Logout',
+ logoutConfirm: 'Confirm Logout',
+ logoutMessage: 'Are you sure you want to logout?',
+ pending: 'Pending',
+ ordered: 'Ordered',
+ arrived: 'Arrived',
+ received: 'Received',
+ },
+ // 登录页
+ login: {
+ title: 'Login',
+ username: 'Username',
+ password: 'Password',
+ rememberMe: 'Remember me',
+ loginBtn: 'Login',
+ logging: 'Logging in...',
+ registerLink: "Don't have an account?",
+ forgotLink: 'Forgot password?',
+ usernamePlaceholder: 'Enter username',
+ passwordPlaceholder: 'Enter password',
+ // 错误提示
+ usernameRequired: 'Please enter username',
+ passwordRequired: 'Please enter password',
+ loginSuccess: 'Login successful',
+ loginFailed: 'Login failed, please check username and password',
+ networkError: 'Network error, please try again later',
+ usernameNotFound: 'Username not found',
+ passwordIncorrect: 'Username or password incorrect',
+ paramError: 'Parameter error',
+ requestFailed: 'Request failed',
+ },
+ // 注册页
+ register: {
+ title: 'Register',
+ username: 'Username',
+ email: 'Email',
+ password: 'Password',
+ confirmPassword: 'Confirm Password',
+ registerBtn: 'Register',
+ registering: 'Registering...',
+ loginLink: 'Already have an account?',
+ usernamePlaceholder: 'Enter username',
+ emailPlaceholder: 'Enter email',
+ passwordPlaceholder: 'Enter password',
+ confirmPlaceholder: 'Confirm password',
+ showPassword: 'Show password',
+ hidePassword: 'Hide password',
+ // 验证提示
+ usernameRequired: 'Please enter username',
+ emailRequired: 'Please enter email',
+ emailInvalid: 'Invalid email format',
+ passwordRequired: 'Please enter password',
+ passwordLength: 'Password must be at least 6 characters',
+ confirmRequired: 'Please confirm password',
+ passwordMismatch: 'Passwords do not match',
+ // 结果提示
+ usernameExists: 'Username already exists',
+ emailUsed: 'Email already in use',
+ paramError: 'Parameter error',
+ requestFailed: 'Request failed',
+ registerSuccess: 'Registration successful',
+ registerFailed: 'Registration failed, please try again later',
+ },
+ // API 配置页
+ apiConfig: {
+ title: 'Settings',
+ apiUrl: 'API Server URL',
+ apiUrlPlaceholder: 'Enter API address',
+ format: 'Format',
+ current: 'Current',
+ notSet: 'Not set',
+ save: 'Save',
+ saveSuccess: 'Saved successfully',
+ pleaseInput: 'Please enter API address',
+ testConnection: 'Test Connection',
+ testBtn: 'Test Connection',
+ testing: 'Testing...',
+ connectionSuccess: 'Connection successful',
+ connectionFailed: 'Connection failed',
+ language: 'Language',
+ zh: '中文',
+ en: 'English',
+ },
+ // 通用
+ common: {
+ loading: 'Loading...',
+ error: 'Request failed',
+ retry: 'Retry',
+ confirm: 'Confirm',
+ cancel: 'Cancel',
+ success: 'Operation successful',
+ failed: 'Operation failed',
+ back: 'Back',
+ networkError: 'Network request failed, please check your connection',
+ }
+}
diff --git a/frontend/ops_uniapp/locales/index.js b/frontend/ops_uniapp/locales/index.js
new file mode 100644
index 0000000..6eb7965
--- /dev/null
+++ b/frontend/ops_uniapp/locales/index.js
@@ -0,0 +1,47 @@
+import { createI18n } from 'vue-i18n'
+import zh from './zh.js'
+import en from './en.js'
+
+// 获取本地语言设置,默认中文
+function getLocale() {
+ // 从本地存储读取
+ const stored = uni.getStorageSync('locale')
+ if (stored) return stored
+
+ // 获取系统语言
+ const sysInfo = uni.getSystemInfoSync()
+ const sysLang = sysInfo.language || 'zh-CN'
+ // 简单判断:是否以 zh 开头
+ return sysLang.toLowerCase().startsWith('zh') ? 'zh' : 'en'
+}
+
+// 创建 i18n 实例
+export const i18n = createI18n({
+ legacy: false, // uni-app 必须用 composition API 模式
+ locale: getLocale(),
+ fallbackLocale: 'zh',
+ messages: {
+ zh,
+ en
+ }
+})
+
+// 切换语言
+export function setLocale(locale) {
+ if (i18n.global.locale && typeof i18n.global.locale.value !== 'undefined') {
+ i18n.global.locale.value = locale
+ } else {
+ i18n.global.locale = locale
+ }
+ uni.setStorageSync('locale', locale)
+ // 触发页面更新
+ uni.$emit('localeChanged', locale)
+}
+
+// 获取当前语言
+export function getCurrentLocale() {
+ if (i18n.global.locale && typeof i18n.global.locale.value !== 'undefined') {
+ return i18n.global.locale.value
+ }
+ return i18n.global.locale
+}
diff --git a/frontend/ops_uniapp/locales/zh.js b/frontend/ops_uniapp/locales/zh.js
new file mode 100644
index 0000000..3a7bd3d
--- /dev/null
+++ b/frontend/ops_uniapp/locales/zh.js
@@ -0,0 +1,111 @@
+export default {
+ // tabBar
+ tabBar: {
+ home: '首页',
+ settings: '设置',
+ },
+ // 首页
+ index: {
+ welcome: '欢迎使用 OPS',
+ subtitle: '运营管理系统',
+ quickActions: '快捷操作',
+ allOrders: '全部订单',
+ addOrder: '新建订单',
+ schedule: '日程管理',
+ language: '语言',
+ logout: '退出登录',
+ logoutConfirm: '确认退出',
+ logoutMessage: '确定要退出登录吗?',
+ pending: '待处理',
+ ordered: '已下单',
+ arrived: '已到达',
+ received: '已收件',
+ },
+ // 登录页
+ login: {
+ title: '登录',
+ username: '用户名',
+ password: '密码',
+ rememberMe: '记住登录状态',
+ loginBtn: '登 录',
+ logging: '登录中...',
+ registerLink: '没有账号?立即注册',
+ forgotLink: '忘记密码?',
+ usernamePlaceholder: '请输入用户名',
+ passwordPlaceholder: '请输入密码',
+ // 错误提示
+ usernameRequired: '请输入用户名',
+ passwordRequired: '请输入密码',
+ loginSuccess: '登录成功',
+ loginFailed: '登录失败,请检查用户名和密码',
+ networkError: '网络错误,请稍后重试',
+ usernameNotFound: '用户名不存在',
+ passwordIncorrect: '用户名或密码错误',
+ paramError: '参数错误',
+ requestFailed: '请求失败',
+ },
+ // 注册页
+ register: {
+ title: '注册',
+ username: '用户名',
+ email: '邮箱',
+ password: '密码',
+ confirmPassword: '确认密码',
+ registerBtn: '注 册',
+ registering: '注册中...',
+ loginLink: '已有账号?立即登录',
+ usernamePlaceholder: '请输入用户名',
+ emailPlaceholder: '请输入邮箱',
+ passwordPlaceholder: '请输入密码',
+ confirmPlaceholder: '请再次输入密码',
+ showPassword: '显示密码',
+ hidePassword: '隐藏密码',
+ // 验证提示
+ usernameRequired: '请输入用户名',
+ emailRequired: '请输入邮箱',
+ emailInvalid: '邮箱格式不正确',
+ passwordRequired: '请输入密码',
+ passwordLength: '密码至少6位',
+ confirmRequired: '请确认密码',
+ passwordMismatch: '两次密码输入不一致',
+ // 结果提示
+ usernameExists: '用户名已存在',
+ emailUsed: '邮箱已被使用',
+ paramError: '参数错误',
+ requestFailed: '请求失败',
+ registerSuccess: '注册成功',
+ registerFailed: '注册失败,请稍后重试',
+ },
+ // API 配置页
+ apiConfig: {
+ title: '设置',
+ apiUrl: 'API 服务器地址',
+ apiUrlPlaceholder: '请输入 API 地址',
+ format: '格式',
+ current: '当前',
+ notSet: '未设置',
+ save: '保存配置',
+ saveSuccess: '保存成功',
+ pleaseInput: '请输入 API 地址',
+ testConnection: '测试连接',
+ testBtn: '测试连接',
+ testing: '测试中...',
+ connectionSuccess: '连接成功',
+ connectionFailed: '连接失败',
+ language: '语言设置',
+ zh: '中文',
+ en: 'English',
+ },
+ // 通用
+ common: {
+ loading: '加载中...',
+ error: '请求失败',
+ retry: '重试',
+ confirm: '确定',
+ cancel: '取消',
+ success: '操作成功',
+ failed: '操作失败',
+ back: '返回',
+ networkError: '网络请求失败,请检查网络',
+ }
+}
diff --git a/frontend/ops_uniapp/main.js b/frontend/ops_uniapp/main.js
index c1caf36..788ba8d 100644
--- a/frontend/ops_uniapp/main.js
+++ b/frontend/ops_uniapp/main.js
@@ -1,12 +1,21 @@
import App from './App'
+import { i18n } from './locales/index.js'
+
+// 默认 API 地址
+const DEFAULT_API_URL = 'http://192.168.13.105/api/'
// #ifndef VUE3
import Vue from 'vue'
import './uni.promisify.adaptor'
Vue.config.productionTip = false
-App.mpType = 'app'
+
+// 从本地存储读取用户配置的 API 地址
+Vue.prototype.$BASE_URL = uni.getStorageSync('apiUrl') || DEFAULT_API_URL
+Vue.prototype.$i18n = i18n
+
const app = new Vue({
- ...App
+ ...App,
+ i18n
})
app.$mount()
// #endif
@@ -15,8 +24,12 @@ app.$mount()
import { createSSRApp } from 'vue'
export function createApp() {
const app = createSSRApp(App)
+ app.use(i18n)
+ // 从本地存储读取用户配置的 API 地址
+ app.config.globalProperties.$BASE_URL = uni.getStorageSync('apiUrl') || DEFAULT_API_URL
+ app.config.globalProperties.BASE_URL = uni.getStorageSync('apiUrl') || DEFAULT_API_URL
return {
app
}
}
-// #endif
\ No newline at end of file
+// #endif
diff --git a/frontend/ops_uniapp/manifest.json b/frontend/ops_uniapp/manifest.json
index 2de3326..83f1292 100644
--- a/frontend/ops_uniapp/manifest.json
+++ b/frontend/ops_uniapp/manifest.json
@@ -1,7 +1,7 @@
{
- "name" : "ops_uniapp",
+ "name" : "Operations",
"appid" : "",
- "description" : "",
+ "description" : "Operations(运营)的缩写,一个前后端分离的工作流/运营管理系统。",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
@@ -17,7 +17,10 @@
"delay" : 0
},
/* 模块配置 */
- "modules" : {},
+ "modules" : {
+ "Barcode" : {},
+ "Camera" : {}
+ },
/* 应用发布信息 */
"distribute" : {
/* android打包配置 */
@@ -43,7 +46,47 @@
/* ios打包配置 */
"ios" : {},
/* SDK配置 */
- "sdkConfigs" : {}
+ "sdkConfigs" : {},
+ "icons" : {
+ "android" : {
+ "hdpi" : "unpackage/res/icons/72x72.png",
+ "xhdpi" : "unpackage/res/icons/96x96.png",
+ "xxhdpi" : "unpackage/res/icons/144x144.png",
+ "xxxhdpi" : "unpackage/res/icons/192x192.png"
+ },
+ "ios" : {
+ "appstore" : "unpackage/res/icons/1024x1024.png",
+ "ipad" : {
+ "app" : "unpackage/res/icons/76x76.png",
+ "app@2x" : "unpackage/res/icons/152x152.png",
+ "notification" : "unpackage/res/icons/20x20.png",
+ "notification@2x" : "unpackage/res/icons/40x40.png",
+ "proapp@2x" : "unpackage/res/icons/167x167.png",
+ "settings" : "unpackage/res/icons/29x29.png",
+ "settings@2x" : "unpackage/res/icons/58x58.png",
+ "spotlight" : "unpackage/res/icons/40x40.png",
+ "spotlight@2x" : "unpackage/res/icons/80x80.png"
+ },
+ "iphone" : {
+ "app@2x" : "unpackage/res/icons/120x120.png",
+ "app@3x" : "unpackage/res/icons/180x180.png",
+ "notification@2x" : "unpackage/res/icons/40x40.png",
+ "notification@3x" : "unpackage/res/icons/60x60.png",
+ "settings@2x" : "unpackage/res/icons/58x58.png",
+ "settings@3x" : "unpackage/res/icons/87x87.png",
+ "spotlight@2x" : "unpackage/res/icons/80x80.png",
+ "spotlight@3x" : "unpackage/res/icons/120x120.png"
+ }
+ }
+ },
+ "splashscreen" : {
+ "androidStyle" : "default",
+ "android" : {
+ "hdpi" : "static/logo.png",
+ "xhdpi" : "static/logo.png",
+ "xxhdpi" : "static/logo.png"
+ }
+ }
}
},
/* 快应用特有相关 */
@@ -68,5 +111,6 @@
"uniStatistics" : {
"enable" : false
},
- "vueVersion" : "3"
+ "vueVersion" : "3",
+ "locale" : "auto"
}
diff --git a/frontend/ops_uniapp/package.json b/frontend/ops_uniapp/package.json
new file mode 100644
index 0000000..d96cedb
--- /dev/null
+++ b/frontend/ops_uniapp/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "ops-uniapp",
+ "version": "1.0.0",
+ "description": "OPS Mobile App",
+ "main": "main.js",
+ "scripts": {
+ "dev": "uni -p h5",
+ "build": "uni build -p h5"
+ },
+ "dependencies": {
+ "@dcloudio/uni-app": "3.0.0-4010520250107001",
+ "vue-i18n": "^9.14.0"
+ },
+ "devDependencies": {
+ "@dcloudio/types": "^3.4.8",
+ "@dcloudio/uni-cli-shared": "3.0.0-4010520250107001",
+ "@dcloudio/uni-h5": "3.0.0-4010520250107001",
+ "@dcloudio/vite-plugin-uni": "3.0.0-4010520250107001",
+ "vite": "^5.4.0"
+ }
+}
diff --git a/frontend/ops_uniapp/pages.json b/frontend/ops_uniapp/pages.json
index 869105d..57334ed 100644
--- a/frontend/ops_uniapp/pages.json
+++ b/frontend/ops_uniapp/pages.json
@@ -1,17 +1,62 @@
{
- "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
+ "easycom": {
+ "autoscan": true,
+ "custom": {
+ "^custom-(.*)": "@/components/custom-$1/custom-$1.vue"
+ }
+ },
+ "pages": [
{
"path": "pages/index/index",
"style": {
- "navigationBarTitleText": "uni-app"
+ "navigationBarTitleText": "首页"
+ }
+ },
+ {
+ "path": "pages/settings/apiConfig",
+ "style": {
+ "navigationBarTitleText": "设置"
+ }
+ },
+ {
+ "path": "pages/login/login",
+ "style": {
+ "navigationBarTitleText": "登录",
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "pages/register/register",
+ "style": {
+ "navigationBarTitleText": "注册"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
- "navigationBarTitleText": "uni-app",
+ "navigationBarTitleText": "OPS",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
+ "tabBar": {
+ "color": "#999999",
+ "selectedColor": "#667eea",
+ "backgroundColor": "#ffffff",
+ "borderStyle": "black",
+ "list": [
+ {
+ "pagePath": "pages/index/index",
+ "text": "首页",
+ "iconPath": "static/tabbar/home.png",
+ "selectedIconPath": "static/tabbar/home-active.png"
+ },
+ {
+ "pagePath": "pages/settings/apiConfig",
+ "text": "设置",
+ "iconPath": "static/tabbar/settings.png",
+ "selectedIconPath": "static/tabbar/settings-active.png"
+ }
+ ]
+ },
"uniIdRouter": {}
}
diff --git a/frontend/ops_uniapp/pages/index/index.vue b/frontend/ops_uniapp/pages/index/index.vue
index ec0ec26..83c0bf4 100644
--- a/frontend/ops_uniapp/pages/index/index.vue
+++ b/frontend/ops_uniapp/pages/index/index.vue
@@ -1,52 +1,308 @@
-
-
-
- {{title}}
-
-
+
+
+
+
+
+
+
+ {{ stats.pending }}
+ {{ t('index.pending') }}
+
+
+ {{ stats.ordered }}
+ {{ t('index.ordered') }}
+
+
+ {{ stats.arrived }}
+ {{ t('index.arrived') }}
+
+
+ {{ stats.received }}
+ {{ t('index.received') }}
+
+
+
+
+
+ {{ t('index.quickActions') }}
+
+
+ 📋
+ {{ t('index.allOrders') }}
+ →
+
+
+ ➕
+ {{ t('index.addOrder') }}
+ →
+
+
+ 📅
+ {{ t('index.schedule') }}
+ →
+
+
+
+
+
+
+
+ 🌐
+
+ {{ t('index.language') }}
+ {{ locale === 'zh' ? '中文' : 'English' }}
+
+ →
+
+
+
+
+
+
+
+
-
-
diff --git a/frontend/ops_uniapp/pages/login/login.vue b/frontend/ops_uniapp/pages/login/login.vue
new file mode 100644
index 0000000..ca33ce7
--- /dev/null
+++ b/frontend/ops_uniapp/pages/login/login.vue
@@ -0,0 +1,394 @@
+
+
+
+
+ 中文
+ |
+ EN
+
+
+
+
+
+ OPS
+ {{ t('login.title') }}
+
+
+
+
+
+ {{ t('login.username') }}
+
+
+
+
+ {{ t('login.password') }}
+
+
+ {{ showPassword ? '👁️' : '👁️🗨️' }}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ errorMsg }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/ops_uniapp/pages/register/register.vue b/frontend/ops_uniapp/pages/register/register.vue
new file mode 100644
index 0000000..ffdf962
--- /dev/null
+++ b/frontend/ops_uniapp/pages/register/register.vue
@@ -0,0 +1,343 @@
+
+
+
+
+ 中文
+ |
+ EN
+
+
+
+
+ ← {{ t('common.back') }}
+
+
+
+ {{ t('register.title') }}
+
+
+ {{ t('register.username') }}
+
+
+
+
+ {{ t('register.email') }}
+
+
+
+
+ {{ t('register.password') }}
+
+
+
+
+ {{ t('register.confirmPassword') }}
+
+
+
+
+ {{ showPassword ? '👁️ ' : '👁️🗨️ ' }}{{ showPassword ? t('register.showPassword') : t('register.hidePassword') }}
+
+
+
+
+
+ {{ errorMsg }}
+
+
+
+
+
+
+
+
diff --git a/frontend/ops_uniapp/pages/settings/apiConfig.vue b/frontend/ops_uniapp/pages/settings/apiConfig.vue
new file mode 100644
index 0000000..1db8b9d
--- /dev/null
+++ b/frontend/ops_uniapp/pages/settings/apiConfig.vue
@@ -0,0 +1,344 @@
+
+
+
+
+
+
+
+ {{ t('apiConfig.apiUrl') }}
+
+
+
+
+
+
+ {{ t('apiConfig.format') }}: http://192.168.1.100/api/
+
+
+
+ {{ t('apiConfig.current') }}: {{ currentApiUrl }}
+
+
+
+
+
+
+
+ {{ t('apiConfig.testConnection') }}
+
+
+
+
+
+ {{ testResult ? t('apiConfig.connectionSuccess') : t('apiConfig.connectionFailed') }}
+
+
+
+
+
+
+ {{ t('apiConfig.language') }}
+
+
+
+ 🇨🇳 {{ t('apiConfig.zh') }}
+
+
+ 🇺🇸 {{ t('apiConfig.en') }}
+
+
+
+
+
+
+
+
+
diff --git a/frontend/ops_uniapp/static/logo.png b/frontend/ops_uniapp/static/logo.png
index b5771e2..3a22158 100644
Binary files a/frontend/ops_uniapp/static/logo.png and b/frontend/ops_uniapp/static/logo.png differ
diff --git a/frontend/ops_uniapp/static/logo.svg b/frontend/ops_uniapp/static/logo.svg
new file mode 100644
index 0000000..74a149f
--- /dev/null
+++ b/frontend/ops_uniapp/static/logo.svg
@@ -0,0 +1,491 @@
+
+
+
diff --git a/frontend/ops_uniapp/static/tabbar/home-active.png b/frontend/ops_uniapp/static/tabbar/home-active.png
new file mode 100644
index 0000000..87d5762
Binary files /dev/null and b/frontend/ops_uniapp/static/tabbar/home-active.png differ
diff --git a/frontend/ops_uniapp/static/tabbar/home.png b/frontend/ops_uniapp/static/tabbar/home.png
new file mode 100644
index 0000000..ff77dfe
Binary files /dev/null and b/frontend/ops_uniapp/static/tabbar/home.png differ
diff --git a/frontend/ops_uniapp/static/tabbar/settings-active.png b/frontend/ops_uniapp/static/tabbar/settings-active.png
new file mode 100644
index 0000000..ec8fcf1
Binary files /dev/null and b/frontend/ops_uniapp/static/tabbar/settings-active.png differ
diff --git a/frontend/ops_uniapp/static/tabbar/settings.png b/frontend/ops_uniapp/static/tabbar/settings.png
new file mode 100644
index 0000000..071ee19
Binary files /dev/null and b/frontend/ops_uniapp/static/tabbar/settings.png differ
diff --git a/frontend/ops_uniapp/vite.config.js b/frontend/ops_uniapp/vite.config.js
new file mode 100644
index 0000000..cd18790
--- /dev/null
+++ b/frontend/ops_uniapp/vite.config.js
@@ -0,0 +1,15 @@
+import { defineConfig } from 'vite'
+import uni from '@dcloudio/vite-plugin-uni'
+
+export default defineConfig({
+ plugins: [uni()],
+ server: {
+ proxy: {
+ '/api': {
+ target: 'http://192.168.13.105',
+ changeOrigin: true,
+ rewrite: (path) => path.replace(/^\/api/, '/api')
+ }
+ }
+ }
+})