commit 781d598ae7d51991fc9185f96fb27bcdb597f6fe Author: ch <852066789@qq.com> Date: Wed Aug 27 18:12:34 2025 +0800 feat: 初始化订单审批系统项目- 创建项目基础结构和配置文件 - 添加全局样式和工具函数 - 实现订单状态和审批状态的格式化及颜色处理- 添加金额和日期格式化函数 - 实现防抖和节流函数 - 添加微信小程序环境检查和文件预览URL生成函数 - 实现复制到剪贴板功能 - 添加项目路由配置 - 实现HTTP客户端和拦截器 - 添加订单、审批记录等类型定义 diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..f826b16 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,10 @@ +{ + "permissions": { + "allow": [ + "Bash(npm install)", + "Bash(npm run dev:*)" + ], + "deny": [], + "ask": [] + } +} \ No newline at end of file diff --git a/.env b/.env new file mode 100644 index 0000000..210856b --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +VITE_API_BASE_URL=http://localhost:8080 +VITE_APP_TITLE=订单审批系统 +VITE_FILE_BASE_URL=http://localhost:8080 \ No newline at end of file diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..210856b --- /dev/null +++ b/.env.development @@ -0,0 +1,3 @@ +VITE_API_BASE_URL=http://localhost:8080 +VITE_APP_TITLE=订单审批系统 +VITE_FILE_BASE_URL=http://localhost:8080 \ No newline at end of file diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..09f84c7 --- /dev/null +++ b/.env.production @@ -0,0 +1,3 @@ +VITE_API_BASE_URL=https://your-api-domain.com +VITE_APP_TITLE=订单审批系统 +VITE_FILE_BASE_URL=https://your-api-domain.com \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..85dcda7 --- /dev/null +++ b/README.md @@ -0,0 +1,203 @@ +# 微信小程序H5审批系统 + +基于Vue 3 + TypeScript + Vant 4开发的移动端H5应用,主要用于在微信小程序WebView中运行的订单审批系统。 + +## 项目特性 + +- 🚀 Vue 3 + TypeScript + Vite 开发 +- 📱 Vant 4 移动端组件库 +- 🎯 专为微信小程序WebView优化 +- 📋 订单列表查看和搜索 +- 📄 订单详情展示 +- ✅ 审批操作功能 +- 📊 审批历史记录 +- 📎 附件预览功能 + +## 技术栈 + +- **前端框架**: Vue 3 +- **开发语言**: TypeScript +- **构建工具**: Vite +- **UI组件库**: Vant 4 +- **路由管理**: Vue Router 4 +- **状态管理**: Pinia +- **HTTP客户端**: Axios +- **样式预处理**: Sass + +## 目录结构 + +``` +oms_h5/ +├── public/ # 静态资源 +├── src/ +│ ├── api/ # API接口 +│ ├── components/ # 公共组件 +│ ├── views/ # 页面组件 +│ │ ├── List/ # 列表页面 +│ │ └── Detail/ # 详情页面 +│ ├── store/ # 状态管理 +│ ├── utils/ # 工具函数 +│ ├── types/ # TypeScript类型定义 +│ ├── styles/ # 全局样式 +│ └── router/ # 路由配置 +├── docs/ # 文档和设计稿 +│ └── ui-mockups/ # UI设计图 +├── package.json +└── vite.config.ts +``` + +## 开发环境搭建 + +### 环境要求 + +- Node.js >= 16 +- npm >= 7 或 yarn >= 1.22 + +### 安装依赖 + +```bash +npm install +# 或 +yarn install +``` + +### 启动开发服务器 + +```bash +npm run dev +# 或 +yarn dev +``` + +### 构建生产版本 + +```bash +npm run build +# 或 +yarn build +``` + +### 预览构建结果 + +```bash +npm run preview +# 或 +yarn preview +``` + +## 环境配置 + +项目支持多环境配置,通过`.env`文件管理: + +- `.env` - 通用环境变量 +- `.env.development` - 开发环境 +- `.env.production` - 生产环境 + +主要配置项: + +```bash +VITE_API_BASE_URL=http://localhost:8080 # API基础URL +VITE_APP_TITLE=订单审批系统 # 应用标题 +VITE_FILE_BASE_URL=http://localhost:8080 # 文件服务URL +``` + +## 主要功能 + +### 1. 订单列表 +- ✅ 订单列表展示 +- ✅ 下拉刷新和上拉加载 +- ✅ 搜索功能 +- ✅ 状态筛选 +- ✅ 订单状态标识 + +### 2. 订单详情 +- ✅ 订单基本信息展示 +- ✅ 产品信息列表(软件/硬件/维保) +- ✅ 合同附件展示和预览 +- ✅ 审批历史时间线 + +### 3. 审批操作 +- ✅ 审批通过/驳回 +- ✅ 审批意见输入 +- ✅ 操作结果反馈 + +### 4. 微信小程序适配 +- ✅ WebView环境检测 +- ✅ 移动端样式适配 +- ✅ 触摸手势支持 + +## API接口 + +### 订单列表接口 +``` +POST /project/order/list +``` + +### 订单详情接口 +``` +GET /project/order/h5/approve/:id +``` + +### 审批操作接口 +``` +POST /project/order/order/approve +``` + +## 开发规范 + +### 代码风格 +项目使用ESLint + Prettier进行代码规范检查和格式化。 + +```bash +npm run lint # 代码检查 +npm run type-check # 类型检查 +``` + +### Git提交规范 +建议使用Angular提交信息规范: + +``` +feat: 新增功能 +fix: 修复问题 +docs: 文档更新 +style: 代码格式调整 +refactor: 代码重构 +test: 测试相关 +chore: 构建/工具链更新 +``` + +## 部署说明 + +### 生产构建 +```bash +npm run build +``` + +构建完成后,`dist`目录包含所有静态资源文件。 + +### 服务器配置 +由于是SPA应用,需要配置服务器将所有路由指向`index.html`。 + +#### Nginx配置示例 +```nginx +location / { + try_files $uri $uri/ /index.html; +} +``` + +### 微信小程序配置 +1. 在微信小程序管理后台配置业务域名 +2. 确保HTTPS协议部署 +3. 配置webview组件的src属性 + +## 浏览器兼容性 + +- Chrome >= 64 +- Firefox >= 78 +- Safari >= 12 +- 微信内置浏览器 +- 各主流移动端浏览器 + +## 许可证 + +MIT License \ No newline at end of file diff --git a/auto-imports.d.ts b/auto-imports.d.ts new file mode 100644 index 0000000..a606bd4 --- /dev/null +++ b/auto-imports.d.ts @@ -0,0 +1,87 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// noinspection JSUnusedGlobalSymbols +// Generated by unplugin-auto-import +export {} +declare global { + const EffectScope: typeof import('vue')['EffectScope'] + const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate'] + const computed: typeof import('vue')['computed'] + const createApp: typeof import('vue')['createApp'] + const createPinia: typeof import('pinia')['createPinia'] + const customRef: typeof import('vue')['customRef'] + const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] + const defineComponent: typeof import('vue')['defineComponent'] + const defineStore: typeof import('pinia')['defineStore'] + const effectScope: typeof import('vue')['effectScope'] + const getActivePinia: typeof import('pinia')['getActivePinia'] + const getCurrentInstance: typeof import('vue')['getCurrentInstance'] + const getCurrentScope: typeof import('vue')['getCurrentScope'] + const h: typeof import('vue')['h'] + const inject: typeof import('vue')['inject'] + const isProxy: typeof import('vue')['isProxy'] + const isReactive: typeof import('vue')['isReactive'] + const isReadonly: typeof import('vue')['isReadonly'] + const isRef: typeof import('vue')['isRef'] + const mapActions: typeof import('pinia')['mapActions'] + const mapGetters: typeof import('pinia')['mapGetters'] + const mapState: typeof import('pinia')['mapState'] + const mapStores: typeof import('pinia')['mapStores'] + const mapWritableState: typeof import('pinia')['mapWritableState'] + const markRaw: typeof import('vue')['markRaw'] + const nextTick: typeof import('vue')['nextTick'] + const onActivated: typeof import('vue')['onActivated'] + const onBeforeMount: typeof import('vue')['onBeforeMount'] + const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave'] + const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate'] + const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] + const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] + const onDeactivated: typeof import('vue')['onDeactivated'] + const onErrorCaptured: typeof import('vue')['onErrorCaptured'] + const onMounted: typeof import('vue')['onMounted'] + const onRenderTracked: typeof import('vue')['onRenderTracked'] + const onRenderTriggered: typeof import('vue')['onRenderTriggered'] + const onScopeDispose: typeof import('vue')['onScopeDispose'] + const onServerPrefetch: typeof import('vue')['onServerPrefetch'] + const onUnmounted: typeof import('vue')['onUnmounted'] + const onUpdated: typeof import('vue')['onUpdated'] + const onWatcherCleanup: typeof import('vue')['onWatcherCleanup'] + const provide: typeof import('vue')['provide'] + const reactive: typeof import('vue')['reactive'] + const readonly: typeof import('vue')['readonly'] + const ref: typeof import('vue')['ref'] + const resolveComponent: typeof import('vue')['resolveComponent'] + const setActivePinia: typeof import('pinia')['setActivePinia'] + const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix'] + const shallowReactive: typeof import('vue')['shallowReactive'] + const shallowReadonly: typeof import('vue')['shallowReadonly'] + const shallowRef: typeof import('vue')['shallowRef'] + const storeToRefs: typeof import('pinia')['storeToRefs'] + const toRaw: typeof import('vue')['toRaw'] + const toRef: typeof import('vue')['toRef'] + const toRefs: typeof import('vue')['toRefs'] + const toValue: typeof import('vue')['toValue'] + const triggerRef: typeof import('vue')['triggerRef'] + const unref: typeof import('vue')['unref'] + const useAttrs: typeof import('vue')['useAttrs'] + const useCssModule: typeof import('vue')['useCssModule'] + const useCssVars: typeof import('vue')['useCssVars'] + const useId: typeof import('vue')['useId'] + const useLink: typeof import('vue-router')['useLink'] + const useModel: typeof import('vue')['useModel'] + const useRoute: typeof import('vue-router')['useRoute'] + const useRouter: typeof import('vue-router')['useRouter'] + const useSlots: typeof import('vue')['useSlots'] + const useTemplateRef: typeof import('vue')['useTemplateRef'] + const watch: typeof import('vue')['watch'] + const watchEffect: typeof import('vue')['watchEffect'] + const watchPostEffect: typeof import('vue')['watchPostEffect'] + const watchSyncEffect: typeof import('vue')['watchSyncEffect'] +} +// for type re-export +declare global { + // @ts-ignore + export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue' + import('vue') +} diff --git a/components.d.ts b/components.d.ts new file mode 100644 index 0000000..13e3588 --- /dev/null +++ b/components.d.ts @@ -0,0 +1,27 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// Generated by unplugin-vue-components +// Read more: https://github.com/vuejs/core/pull/3399 +export {} + +declare module 'vue' { + export interface GlobalComponents { + RouterLink: typeof import('vue-router')['RouterLink'] + RouterView: typeof import('vue-router')['RouterView'] + VanButton: typeof import('vant/es')['Button'] + VanEmpty: typeof import('vant/es')['Empty'] + VanField: typeof import('vant/es')['Field'] + VanIcon: typeof import('vant/es')['Icon'] + VanList: typeof import('vant/es')['List'] + VanLoading: typeof import('vant/es')['Loading'] + VanNavBar: typeof import('vant/es')['NavBar'] + VanPopup: typeof import('vant/es')['Popup'] + VanPullRefresh: typeof import('vant/es')['PullRefresh'] + VanSearch: typeof import('vant/es')['Search'] + VanStep: typeof import('vant/es')['Step'] + VanSteps: typeof import('vant/es')['Steps'] + VanTab: typeof import('vant/es')['Tab'] + VanTabs: typeof import('vant/es')['Tabs'] + } +} diff --git a/docs/ui-mockups/README.md b/docs/ui-mockups/README.md new file mode 100644 index 0000000..069a871 --- /dev/null +++ b/docs/ui-mockups/README.md @@ -0,0 +1,72 @@ +# UI设计图存放目录 + +此目录用于存放项目相关的UI设计图和原型图。 + +## 目录结构 + +``` +ui-mockups/ +├── README.md # 本文件 +├── wireframes/ # 线框图 +│ ├── list-page.png # 列表页面线框图 +│ └── detail-page.png # 详情页面线框图 +├── designs/ # 设计稿 +│ ├── list-page.png # 列表页面设计稿 +│ └── detail-page.png # 详情页面设计稿 +├── prototypes/ # 交互原型 +└── specifications/ # 设计规范 + └── style-guide.md # 样式指南 +``` + +## 设计要求 + +### 1. 移动端适配 +- 屏幕宽度:375px - 414px +- 适配iPhone和Android主流设备 +- 支持横竖屏切换 + +### 2. 微信小程序WebView适配 +- 适配微信小程序导航栏高度 +- 考虑安全区域(刘海屏等) +- 遵循微信小程序设计规范 + +### 3. 页面设计规范 + +#### 列表页面 +- 顶部搜索栏 +- 筛选条件(状态筛选) +- 工单卡片列表 +- 下拉刷新、上拉加载更多 +- 空状态提示 + +#### 详情页面 +- 工单基本信息展示 +- 产品信息列表 +- 附件展示区域 +- 审批历史时间线 +- 底部审批操作按钮 + +### 4. 交互设计 +- 页面切换动画 +- 加载状态提示 +- 操作反馈(成功/失败提示) +- 确认弹窗设计 + +### 5. 视觉设计 +- 主色调:#1890ff(蓝色) +- 辅助色:#52c41a(成功绿)、#f5222d(错误红) +- 背景色:#f5f5f5 +- 文字颜色:#333333(主要)、#666666(次要)、#999999(辅助) + +## 文件命名规范 + +- 使用英文命名,单词间用连字符分隔 +- 包含页面/组件名称和版本号 +- 示例:`order-list-v1.0.png`、`approval-dialog-v2.1.png` + +## 版本管理 + +每次设计更新时请: +1. 更新版本号 +2. 在文件名中体现版本 +3. 保留历史版本以便回溯 \ No newline at end of file diff --git a/docs/ui-mockups/designs/2.1.1-审批列表@2x.png b/docs/ui-mockups/designs/2.1.1-审批列表@2x.png new file mode 100644 index 0000000..344f142 Binary files /dev/null and b/docs/ui-mockups/designs/2.1.1-审批列表@2x.png differ diff --git a/docs/ui-mockups/designs/2.2.1-审批详情@2x.png b/docs/ui-mockups/designs/2.2.1-审批详情@2x.png new file mode 100644 index 0000000..144f7e4 Binary files /dev/null and b/docs/ui-mockups/designs/2.2.1-审批详情@2x.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..2a3a9e4 --- /dev/null +++ b/index.html @@ -0,0 +1,30 @@ + + +
+ + + + + + +