diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f71b978 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +node_modules/ +.DS_Store +.idea/ +.vscode/ +.env +.env.local + + +package-lock.json +yarn.lock diff --git a/h5/README.md b/h5/README.md new file mode 100644 index 0000000..06efde7 --- /dev/null +++ b/h5/README.md @@ -0,0 +1,102 @@ +# H5在线缴费系统 + +基于Vue.js和Vant UI的移动端在线缴费系统,提供账单管理、缴费支付、对账等功能。 + +## 主要功能 + +- 缴费账单列表查询:查询当前业户待缴费的账单 +- 预缴账单列表查询:查询当前业户未到期的预缴账单 +- 缴费支付:支持个对公和公对公两种支付方式 +- 缴费记录查询:查询历史缴费记录 +- 支付结果查询:查询支付状态 +- 其他辅助功能 + +## 技术栈 + +- Vue 2.6.x +- Vuex +- Vue Router +- Vant UI +- Axios +- Sass +- ES6+ + +## 项目结构 + +``` +├── public/ # 静态资源目录 +├── src/ # 源代码目录 +│ ├── api/ # API接口定义 +│ ├── assets/ # 静态资源文件 +│ ├── components/ # 公共组件 +│ ├── router/ # 路由配置 +│ ├── store/ # Vuex状态管理 +│ ├── utils/ # 工具函数 +│ ├── views/ # 页面组件 +│ ├── App.vue # 根组件 +│ └── main.js # 入口文件 +├── .env.development # 开发环境配置 +├── .env.production # 生产环境配置 +├── babel.config.js # Babel配置 +├── postcss.config.js # PostCSS配置 +└── vue.config.js # Vue CLI配置 +``` + +## 快速开始 + +### 安装依赖 +``` +npm install +``` + +### 开发模式 +``` +npm run dev +``` + +### 生产构建 +``` +npm run build +``` + +### 代码格式化 +``` +npm run lint +``` + +## 组件说明 + +### 主要页面组件 + +- `Index.vue`: 在线缴费首页,显示待缴费账单列表 +- `PrepayBills.vue`: 预缴账单页面,显示未到期的预缴账单 +- `Records.vue`: 缴费记录页面,显示历史缴费记录 +- `BillDetail.vue`: 账单详情页,显示账单详细信息 +- `RecordDetail.vue`: 缴费记录详情页,显示缴费记录详细信息 +- `EnterprisePay.vue`: 公对公支付页面,提供公对公支付链接 +- `PayResult.vue`: 支付结果页面,显示支付结果信息 + +### 公共组件 + +- `PayerSelector.vue`: 业户选择器组件,用于选择当前操作的业户 + +## 业务规则 + +### 缴费流程 + +1. 用户在账单列表页选择需要缴费的账单 +2. 选择支付方式(个对公/公对公) +3. 系统生成支付订单 +4. 用户完成支付 +5. 系统更新账单状态和缴费记录 + +### 公对公支付 + +1. 用户选择公对公支付方式后,系统生成支付链接 +2. 支付链接有效期为5分钟 +3. 用户复制链接后在浏览器中打开完成支付 +4. 系统自动更新支付状态 + +## API文档 + +详细的API接口文档请参考后端开发文档。 \ No newline at end of file diff --git a/h5/babel.config.js b/h5/babel.config.js new file mode 100644 index 0000000..f707b32 --- /dev/null +++ b/h5/babel.config.js @@ -0,0 +1,5 @@ +module.exports = { + presets: [ + '@vue/cli-plugin-babel/preset' + ] +}; \ No newline at end of file diff --git a/h5/package.json b/h5/package.json new file mode 100644 index 0000000..f37ff90 --- /dev/null +++ b/h5/package.json @@ -0,0 +1,81 @@ +{ + "name": "U-H5", + "version": "1.0.0", + "private": true, + "author": { + "name": "zzz" + }, + "scripts": { + "dev": "vue-cli-service serve --mode development", + "build": "vue-cli-service build --mode production", + "lint": "vue-cli-service lint", + "lint-fix": "vue-cli-service lint ./src --ext .vue,.js", + "prepare": "husky install" + }, + "dependencies": { + "@vant/area-data": "^1.2.1", + "axios": "^0.27.2", + "clipboard": "^2.0.11", + "echarts": "^5.5.1", + "file-saver": "^2.0.5", + "jszip": "^3.10.1", + "qrcode": "^1.5.3", + "qs": "^6.10.3", + "tui-image-editor": "^3.15.3", + "vant": "^2.13.1", + "vue": "^2.6.14", + "vue-draggable-resizable": "^2.3.0", + "vue-router": "^3.5.4", + "vue-wechat-title": "^2.0.7", + "vuedraggable": "^2.24.3", + "vuex": "^3.6.2", + "weixin-js-sdk": "^1.4.0-test" + }, + "devDependencies": { + "@babel/core": "^7.12.16", + "@babel/eslint-parser": "^7.12.16", + "@vue/cli-plugin-babel": "~5.0.0", + "@vue/cli-plugin-eslint": "~5.0.0", + "@vue/cli-service": "~5.0.0", + "@vue/eslint-config-airbnb": "^5.0.2", + "autoprefixer": "^10.4.7", + "babel-plugin-import": "^1.13.3", + "compression-webpack-plugin": "^6.1.1", + "core-js": "^3.23.2", + "eslint": "^7.32.0", + "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-import": "^2.25.3", + "eslint-plugin-prettier": "^4.0.0", + "eslint-plugin-vue": "^8.0.3", + "eslint-plugin-vuejs-accessibility": "^1.1.0", + "husky": "^7.0.2", + "lint-staged": "^11.1.2", + "postcss-px-to-viewport": "^1.1.1", + "prettier": "^2.7.1", + "sass": "^1.53.0", + "sass-loader": "^13.0.0", + "style-resources-loader": "^1.5.0", + "vue-template-compiler": "^2.6.14", + "webpack-bundle-analyzer": "^4.5.0" + }, + "eslintConfig": { + "root": true, + "env": { + "node": true + }, + "extends": [ + "plugin:vue/essential", + "eslint:recommended" + ], + "parserOptions": { + "parser": "@babel/eslint-parser" + }, + "rules": {} + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not dead" + ] +} diff --git a/h5/postcss.config.js b/h5/postcss.config.js new file mode 100644 index 0000000..5659fd4 --- /dev/null +++ b/h5/postcss.config.js @@ -0,0 +1,16 @@ +module.exports = { + plugins: { + 'postcss-px-to-viewport': { + viewportWidth: 375, // 视窗的宽度,对应的是我们设计稿的宽度 + viewportHeight: 667, // 视窗的高度,根据750设备的宽度来指定,一般指定1334 + unitPrecision: 3, // 指定`px`转换为视窗单位值的小数位数 + viewportUnit: 'vw', // 指定需要转换成的视窗单位,建议使用vw + selectorBlackList: ['.ignore', '.hairlines'], // 指定不转换为视窗单位的类,可以自定义,可以无限添加,建议定义一至两个通用的类名 + minPixelValue: 1, // 小于或等于`1px`不转换为视窗单位,你也可以设置为你想要的值 + mediaQuery: false // 允许在媒体查询中转换`px` + }, + 'autoprefixer': { + browsers: ['Android >= 4.0', 'iOS >= 8'] + } + } +}; \ No newline at end of file diff --git a/h5/public/index.html b/h5/public/index.html new file mode 100644 index 0000000..acd7df0 --- /dev/null +++ b/h5/public/index.html @@ -0,0 +1,36 @@ + + + + + + + + <%= htmlWebpackPlugin.options.title %> + + + + + +
+ + + \ No newline at end of file diff --git a/h5/src/App.vue b/h5/src/App.vue new file mode 100644 index 0000000..f11aedf --- /dev/null +++ b/h5/src/App.vue @@ -0,0 +1,23 @@ + + + + + \ No newline at end of file diff --git a/h5/src/api/payment.js b/h5/src/api/payment.js new file mode 100644 index 0000000..99f429c --- /dev/null +++ b/h5/src/api/payment.js @@ -0,0 +1,50 @@ +import { request } from '@/utils/request'; + +const api = { + // 查询缴费账单列表 + getBills(params) { + return request.post('/payment/bills', params); + }, + + // 查询预缴账单列表 + getPrepayBills(params) { + return request.post('/payment/prepay-bills', params); + }, + + // 查询账单详情 + getBillDetail(billId, config = { showLoading: false }) { + return request.get(`/payment/bill-detail/${billId}`, null, config); + }, + + // 查询缴费记录 + getPaymentRecords(params) { + return request.post('/payment/records', params); + }, + + // 查询缴费记录详情 + getRecordDetail(billId, config) { + return request.get(`/payment/record-detail/${billId}`, null, config); + }, + + // 创建支付订单 + createPayOrder(data) { + return request.post('/payment/create-order', data); + }, + + // 查询支付结果 + queryPayResult(orderNo) { + return request.get(`/payment/order-result/${orderNo}`); + }, + + // 取消支付订单 + cancelOrder(orderNo) { + return request.post(`/payment/cancel-order/${orderNo}`); + }, + + // 获取公对公支付链接 + getEnterprisePayUrl(orderNo) { + return request.get(`/payment/enterprise-pay-url/${orderNo}`); + }, +}; + +export default api; \ No newline at end of file diff --git a/h5/src/api/user.js b/h5/src/api/user.js new file mode 100644 index 0000000..9a497f4 --- /dev/null +++ b/h5/src/api/user.js @@ -0,0 +1,15 @@ +import { request } from '@/utils/request'; + +const api = { + // 获取用户信息 + getUserInfo() { + return request.get('/user/info'); + }, + + // 获取业户列表 + getPayerList() { + return request.get('/user/payer-list'); + }, +}; + +export default api; \ No newline at end of file diff --git a/h5/src/assets/styles/index.scss b/h5/src/assets/styles/index.scss new file mode 100644 index 0000000..e6f26d8 --- /dev/null +++ b/h5/src/assets/styles/index.scss @@ -0,0 +1,268 @@ +html, body { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + font-size: 16px; + font-family: 'PingFang SC', 'Helvetica Neue', Helvetica, Arial, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + background-color: #f5f5f5; + color: #333; +} + +* { + box-sizing: border-box; +} + +/* 常用颜色 */ +:root { + --primary-color: #1989fa; + --success-color: #07c160; + --warning-color: #ff976a; + --danger-color: #ee0a24; + --info-color: #909399; + --background-color: #f5f5f5; + --text-color: #323233; + --text-color-light: #969799; + --border-color: #ebedf0; +} + +/* 常用间距 */ +.m-0 { margin: 0; } +.m-1 { margin: 4px; } +.m-2 { margin: 8px; } +.m-3 { margin: 12px; } +.m-4 { margin: 16px; } +.m-5 { margin: 20px; } + +.mt-0 { margin-top: 0; } +.mt-1 { margin-top: 4px; } +.mt-2 { margin-top: 8px; } +.mt-3 { margin-top: 12px; } +.mt-4 { margin-top: 16px; } +.mt-5 { margin-top: 20px; } + +.mb-0 { margin-bottom: 0; } +.mb-1 { margin-bottom: 4px; } +.mb-2 { margin-bottom: 8px; } +.mb-3 { margin-bottom: 12px; } +.mb-4 { margin-bottom: 16px; } +.mb-5 { margin-bottom: 20px; } + +.ml-0 { margin-left: 0; } +.ml-1 { margin-left: 4px; } +.ml-2 { margin-left: 8px; } +.ml-3 { margin-left: 12px; } +.ml-4 { margin-left: 16px; } +.ml-5 { margin-left: 20px; } + +.mr-0 { margin-right: 0; } +.mr-1 { margin-right: 4px; } +.mr-2 { margin-right: 8px; } +.mr-3 { margin-right: 12px; } +.mr-4 { margin-right: 16px; } +.mr-5 { margin-right: 20px; } + +.p-0 { padding: 0; } +.p-1 { padding: 4px; } +.p-2 { padding: 8px; } +.p-3 { padding: 12px; } +.p-4 { padding: 16px; } +.p-5 { padding: 20px; } + +.pt-0 { padding-top: 0; } +.pt-1 { padding-top: 4px; } +.pt-2 { padding-top: 8px; } +.pt-3 { padding-top: 12px; } +.pt-4 { padding-top: 16px; } +.pt-5 { padding-top: 20px; } + +.pb-0 { padding-bottom: 0; } +.pb-1 { padding-bottom: 4px; } +.pb-2 { padding-bottom: 8px; } +.pb-3 { padding-bottom: 12px; } +.pb-4 { padding-bottom: 16px; } +.pb-5 { padding-bottom: 20px; } + +.pl-0 { padding-left: 0; } +.pl-1 { padding-left: 4px; } +.pl-2 { padding-left: 8px; } +.pl-3 { padding-left: 12px; } +.pl-4 { padding-left: 16px; } +.pl-5 { padding-left: 20px; } + +.pr-0 { padding-right: 0; } +.pr-1 { padding-right: 4px; } +.pr-2 { padding-right: 8px; } +.pr-3 { padding-right: 12px; } +.pr-4 { padding-right: 16px; } +.pr-5 { padding-right: 20px; } + +/* 常用布局类 */ +.flex { + display: flex; +} + +.flex-column { + flex-direction: column; +} + +.flex-wrap { + flex-wrap: wrap; +} + +.justify-start { + justify-content: flex-start; +} + +.justify-center { + justify-content: center; +} + +.justify-end { + justify-content: flex-end; +} + +.justify-between { + justify-content: space-between; +} + +.justify-around { + justify-content: space-around; +} + +.align-start { + align-items: flex-start; +} + +.align-center { + align-items: center; +} + +.align-end { + align-items: flex-end; +} + +.flex-1 { + flex: 1; +} + +.flex-grow-0 { + flex-grow: 0; +} + +.flex-grow-1 { + flex-grow: 1; +} + +.text-center { + text-align: center; +} + +.text-left { + text-align: left; +} + +.text-right { + text-align: right; +} + +.text-primary { + color: var(--primary-color); +} + +.text-success { + color: var(--success-color); +} + +.text-warning { + color: var(--warning-color); +} + +.text-danger { + color: var(--danger-color); +} + +.text-info { + color: var(--info-color); +} + +.bg-white { + background-color: #fff; +} + +.rounded { + border-radius: 4px; +} + +.rounded-circle { + border-radius: 50%; +} + +.truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.position-relative { + position: relative; +} + +.position-absolute { + position: absolute; +} + +.w-100 { + width: 100%; +} + +.h-100 { + height: 100%; +} + +.divider { + height: 8px; + background-color: var(--background-color); +} + +/* 标题样式 */ +.page-title { + font-size: 18px; + font-weight: 500; + padding: 12px 16px; + border-bottom: 1px solid var(--border-color); + background-color: #fff; + margin: 0; +} + +/* 自定义卡片样式 */ +.card { + background-color: #fff; + border-radius: 8px; + margin: 12px; + padding: 16px; + box-shadow: 0 2px 12px rgba(100, 101, 102, 0.08); +} + +.card-title { + font-size: 16px; + font-weight: 500; + margin: 0 0 12px 0; + padding-bottom: 8px; + border-bottom: 1px solid var(--border-color); +} + +/* 底部操作栏 */ +.footer-action-bar { + position: fixed; + bottom: 0; + left: 0; + right: 0; + z-index: 100; + background-color: #fff; + padding: 10px 16px; + border-top: 1px solid var(--border-color); + box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05); +} \ No newline at end of file diff --git a/h5/src/assets/styles/variables.scss b/h5/src/assets/styles/variables.scss new file mode 100644 index 0000000..5b213b7 --- /dev/null +++ b/h5/src/assets/styles/variables.scss @@ -0,0 +1,101 @@ +// 主题颜色 +$primary-color: #1989fa; +$success-color: #07c160; +$warning-color: #ff976a; +$danger-color: #ee0a24; +$info-color: #909399; + +// 背景颜色 +$background-color: #f5f5f5; +$background-color-light: #fafafa; + +// 文字颜色 +$text-color: #323233; +$text-color-light: #969799; +$text-color-disabled: #c8c9cc; + +// 边框颜色 +$border-color: #ebedf0; +$border-color-dark: #dcdee0; + +// 字体大小 +$font-size-xs: 10px; +$font-size-sm: 12px; +$font-size-md: 14px; +$font-size-lg: 16px; +$font-size-xl: 18px; + +// 边距 +$padding-xs: 4px; +$padding-sm: 8px; +$padding-md: 12px; +$padding-lg: 16px; +$padding-xl: 20px; + +// 圆角 +$border-radius-sm: 2px; +$border-radius-md: 4px; +$border-radius-lg: 8px; +$border-radius-max: 999px; + +// 动画 +$animation-duration-base: 0.3s; +$animation-duration-fast: 0.2s; +$animation-timing-function-enter: ease-out; +$animation-timing-function-leave: ease-in; + +// 阴影 +$shadow-1: 0 2px 4px rgba(0, 0, 0, 0.1); +$shadow-2: 0 4px 8px rgba(0, 0, 0, 0.1); +$shadow-3: 0 8px 16px rgba(0, 0, 0, 0.1); + +// 混合器 +@mixin ellipsis { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +@mixin multi-ellipsis($lines) { + display: -webkit-box; + -webkit-line-clamp: $lines; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; +} + +@mixin hairline-bottom($color: $border-color) { + position: relative; + + &::after { + position: absolute; + box-sizing: border-box; + content: ' '; + pointer-events: none; + bottom: 0; + left: 0; + right: 0; + border-bottom: 1px solid $color; + transform: scaleY(0.5); + } +} + +@mixin flex-center { + display: flex; + justify-content: center; + align-items: center; +} + +@mixin flex-between { + display: flex; + justify-content: space-between; + align-items: center; +} + +@mixin clearfix { + &::after { + content: ''; + display: table; + clear: both; + } +} \ No newline at end of file diff --git a/h5/src/components/PayerSelector.vue b/h5/src/components/PayerSelector.vue new file mode 100644 index 0000000..3ad3d88 --- /dev/null +++ b/h5/src/components/PayerSelector.vue @@ -0,0 +1,81 @@ + + + + + \ No newline at end of file diff --git a/h5/src/env.development.js b/h5/src/env.development.js new file mode 100644 index 0000000..17a94f7 --- /dev/null +++ b/h5/src/env.development.js @@ -0,0 +1,10 @@ +// 开发环境配置 +export default { + NODE_ENV: 'development', + + // API 基础路径 + BASE_API: '/api', + + // 页面标题 + TITLE: '在线缴费系统' +}; \ No newline at end of file diff --git a/h5/src/env.production.js b/h5/src/env.production.js new file mode 100644 index 0000000..ae5db72 --- /dev/null +++ b/h5/src/env.production.js @@ -0,0 +1,10 @@ +// 生产环境配置 +export default { + NODE_ENV: 'production', + + // API 基础路径 + BASE_API: '/api', + + // 页面标题 + TITLE: '在线缴费系统' +}; \ No newline at end of file diff --git a/h5/src/main.js b/h5/src/main.js new file mode 100644 index 0000000..0f786af --- /dev/null +++ b/h5/src/main.js @@ -0,0 +1,25 @@ +import Vue from 'vue'; +import App from './App.vue'; +import router from './router'; +import store from './store'; + +// 完整引入Vant及其样式 +import Vant from 'vant'; +import 'vant/lib/index.css'; + +Vue.use(Vant); + +// 导入全局样式 +import './assets/styles/index.scss'; + +// 全局API请求 +import { request } from './utils/request'; +Vue.prototype.$http = request; + +Vue.config.productionTip = false; + +new Vue({ + router, + store, + render: (h) => h(App), +}).$mount('#app'); \ No newline at end of file diff --git a/h5/src/router/index.js b/h5/src/router/index.js new file mode 100644 index 0000000..f1b7245 --- /dev/null +++ b/h5/src/router/index.js @@ -0,0 +1,75 @@ +import Vue from 'vue'; +import VueRouter from 'vue-router'; +import VueWechatTitle from 'vue-wechat-title'; + +Vue.use(VueRouter); +Vue.use(VueWechatTitle); + +// 路由懒加载 +const routes = [ + { + path: '/', + redirect: '/payment', + }, + { + path: '/payment', + name: 'Payment', + component: () => import('../views/payment/Index.vue'), + meta: { title: '在线缴费' }, + }, + { + path: '/payment/prepay', + name: 'PrepayBills', + component: () => import('../views/payment/PrepayBills.vue'), + meta: { title: '预缴账单' }, + }, + { + path: '/payment/records', + name: 'PaymentRecords', + component: () => import('../views/payment/Records.vue'), + meta: { title: '缴费记录' }, + }, + { + path: '/payment/bill-detail/:billId', + name: 'BillDetail', + component: () => import('../views/payment/BillDetail.vue'), + meta: { title: '账单详情' }, + }, + { + path: '/payment/record-detail/:billId', + name: 'RecordDetail', + component: () => import('../views/payment/RecordDetail.vue'), + meta: { title: '缴费详情' }, + }, + { + path: '/payment/pay-result', + name: 'PayResult', + component: () => import('../views/payment/PayResult.vue'), + meta: { title: '支付结果' }, + }, + { + path: '/payment/enterprise-pay', + name: 'EnterprisePay', + component: () => import('../views/payment/EnterprisePay.vue'), + meta: { title: '公对公支付' }, + }, + { + path: '*', + redirect: '/payment', + }, +]; + +const router = new VueRouter({ + routes, +}); + +// 全局路由守卫 +router.beforeEach((to, from, next) => { + // 更新页面标题 + if (to.meta.title) { + document.title = to.meta.title; + } + next(); +}); + +export default router; \ No newline at end of file diff --git a/h5/src/store/index.js b/h5/src/store/index.js new file mode 100644 index 0000000..0865de4 --- /dev/null +++ b/h5/src/store/index.js @@ -0,0 +1,26 @@ +import Vue from 'vue'; +import Vuex from 'vuex'; +import payment from './modules/payment'; +import user from './modules/user'; + +Vue.use(Vuex); + +export default new Vuex.Store({ + state: { + loading: false, + }, + mutations: { + SET_LOADING(state, loading) { + state.loading = loading; + }, + }, + actions: { + setLoading({ commit }, loading) { + commit('SET_LOADING', loading); + }, + }, + modules: { + payment, + user, + }, +}); \ No newline at end of file diff --git a/h5/src/store/modules/payment.js b/h5/src/store/modules/payment.js new file mode 100644 index 0000000..530379a --- /dev/null +++ b/h5/src/store/modules/payment.js @@ -0,0 +1,217 @@ +import { Toast } from 'vant'; +import api from '@/api/payment'; + +const state = { + bills: [], // 缴费账单列表 + prepayBills: [], // 预缴账单列表 + paymentRecords: [], // 缴费记录 + currentBill: null, // 当前查看的账单详情 + selectedBills: [], // 已选择的账单 + totalAmount: 0, // 总金额 + totalCount: 0, // 总数量 + payerName: '', // 缴费人姓名 + buildingGroups: [], // 楼宇分组 + payType: 'personal', // 支付类型:personal-个对公,enterprise-公对公 +}; + +const mutations = { + SET_BILLS(state, data) { + state.bills = data.bills || []; + state.totalAmount = data.totalAmount || 0; + state.totalCount = data.totalCount || 0; + state.payerName = data.payerName || ''; + state.buildingGroups = data.buildingGroups || []; + }, + SET_PREPAY_BILLS(state, data) { + state.prepayBills = data.bills || []; + state.totalAmount = data.totalAmount || 0; + state.totalCount = data.totalCount || 0; + state.payerName = data.payerName || ''; + state.buildingGroups = data.buildingGroups || []; + }, + SET_PAYMENT_RECORDS(state, records) { + state.paymentRecords = records; + }, + SET_CURRENT_BILL(state, bill) { + state.currentBill = bill; + }, + ADD_SELECTED_BILL(state, bill) { + // 保留已选择的其他费用类型账单,但替换同一费用类型下的账单 + const existingBillsFromOtherTypes = state.selectedBills.filter(item => + item.feeTypeName !== bill.feeTypeName || + item.buildingId !== bill.buildingId + ); + + // 将当前账单加入到已选择的账单列表中 + state.selectedBills = [...existingBillsFromOtherTypes, bill]; + }, + REMOVE_SELECTED_BILL(state, billId) { + state.selectedBills = state.selectedBills.filter(bill => bill.billId !== billId); + }, + CLEAR_SELECTED_BILLS(state) { + state.selectedBills = []; + }, + SET_PAY_TYPE(state, type) { + state.payType = type; + }, +}; + +const actions = { + // 获取缴费账单列表 + async getBills({ commit }, params) { + try { + const response = await api.getBills(params); + if (response.code === '0000000000000000') { + commit('SET_BILLS', response.data); + return response.data; + } else { + Toast.fail(response.message || '获取账单列表失败'); + return null; + } + } catch (error) { + Toast.fail('获取账单列表失败'); + return null; + } + }, + + // 获取预缴账单列表 + async getPrepayBills({ commit }, params) { + try { + const response = await api.getPrepayBills(params); + if (response.code === '0000000000000000') { + commit('SET_PREPAY_BILLS', response.data); + return response.data; + } else { + Toast.fail(response.message || '获取预缴账单列表失败'); + return null; + } + } catch (error) { + Toast.fail('获取预缴账单列表失败'); + return null; + } + }, + + // 获取缴费记录 + async getPaymentRecords({ commit }, params) { + try { + const response = await api.getPaymentRecords(params); + if (response.code === '0000000000000000') { + commit('SET_PAYMENT_RECORDS', response.data.list || []); + return response.data; + } else { + Toast.fail(response.message || '获取缴费记录失败'); + return null; + } + } catch (error) { + Toast.fail('获取缴费记录失败'); + return null; + } + }, + + // 获取账单详情 + async getBillDetail({ commit }, billId) { + try { + const response = await api.getBillDetail(billId); + if (response.code === '0000000000000000') { + commit('SET_CURRENT_BILL', response.data); + return response.data; + } else { + Toast.fail(response.message || '获取账单详情失败'); + return null; + } + } catch (error) { + Toast.fail('获取账单详情失败'); + return null; + } + }, + + // 获取缴费记录详情 + async getRecordDetail({ commit }, billId) { + try { + const response = await api.getRecordDetail(billId); + if (response.code === '0000000000000000') { + commit('SET_CURRENT_BILL', response.data); + return response.data; + } else { + Toast.fail(response.message || '获取缴费记录详情失败'); + return null; + } + } catch (error) { + Toast.fail('获取缴费记录详情失败'); + return null; + } + }, + + // 创建支付订单 + async createPayOrder({ state }) { + if (state.selectedBills.length === 0) { + Toast.fail('请选择需要缴费的账单'); + return null; + } + + try { + const billIds = state.selectedBills.map(bill => bill.billId); + const payType = state.payType; + + const response = await api.createPayOrder({ + billIds, + payType, + }); + + if (response.code === '0000000000000000') { + return response.data; + } else { + Toast.fail(response.message || '创建支付订单失败'); + return null; + } + } catch (error) { + Toast.fail('创建支付订单失败'); + return null; + } + }, + + // 查询支付结果 + async queryPayResult({ commit }, orderNo) { + try { + const response = await api.queryPayResult(orderNo); + return response.data; + } catch (error) { + Toast.fail('查询支付结果失败'); + return null; + } + }, + + // 取消订单 + async cancelOrder(_, orderNo) { + try { + const response = await api.cancelOrder(orderNo); + if (response.code === '0000000000000000') { + Toast.success('取消订单成功'); + return true; + } else { + Toast.fail(response.message || '取消订单失败'); + return false; + } + } catch (error) { + Toast.fail('取消订单失败'); + return false; + } + }, +}; + +const getters = { + selectedBillsTotalAmount(state) { + return state.selectedBills.reduce((total, bill) => total + bill.totalNeedAmount, 0); + }, + selectedBillsCount(state) { + return state.selectedBills.length; + }, +}; + +export default { + namespaced: true, + state, + mutations, + actions, + getters, +}; \ No newline at end of file diff --git a/h5/src/store/modules/user.js b/h5/src/store/modules/user.js new file mode 100644 index 0000000..6d36663 --- /dev/null +++ b/h5/src/store/modules/user.js @@ -0,0 +1,107 @@ +import { Toast } from 'vant'; +import api from '@/api/user'; + +const state = { + userInfo: null, // 用户信息 + currentPayer: null, // 当前选择的业户 + payerList: [], // 业户列表 +}; + +const mutations = { + SET_USER_INFO(state, userInfo) { + state.userInfo = userInfo; + }, + SET_CURRENT_PAYER(state, payer) { + state.currentPayer = payer; + // 将当前选择的业户ID保存到localStorage + if (payer) { + localStorage.setItem('currentPayerId', payer.id); + } else { + localStorage.removeItem('currentPayerId'); + } + }, + SET_PAYER_LIST(state, list) { + state.payerList = list; + }, +}; + +const actions = { + // 获取用户信息 +// async getUserInfo({ commit }) { +// try { +// const response = await api.getUserInfo(); +// if (response.code === '0000000000000000') { +// commit('SET_USER_INFO', response.data); +// return response.data; +// } else { +// Toast.fail(response.message || '获取用户信息失败'); +// return null; +// } +// } catch (error) { +// Toast.fail('获取用户信息失败'); +// return null; +// } +// }, + +// // 获取业户列表 +// async getPayerList({ commit }) { +// try { +// const response = await api.getPayerList(); +// if (response.code === '0000000000000000') { +// const payerList = response.data || []; +// commit('SET_PAYER_LIST', payerList); + +// // 如果localStorage中有保存的业户ID,则自动选择 +// const savedPayerId = localStorage.getItem('currentPayerId'); +// if (savedPayerId && payerList.length > 0) { +// const savedPayer = payerList.find(payer => payer.id === Number(savedPayerId)); +// if (savedPayer) { +// commit('SET_CURRENT_PAYER', savedPayer); +// } else { +// // 如果没找到保存的业户,则选择第一个 +// commit('SET_CURRENT_PAYER', payerList[0]); +// } +// } else if (payerList.length > 0) { +// // 默认选择第一个业户 +// commit('SET_CURRENT_PAYER', payerList[0]); +// } + +// return payerList; +// } else { +// Toast.fail(response.message || '获取业户列表失败'); +// return []; +// } +// } catch (error) { +// Toast.fail('获取业户列表失败'); +// return []; +// } +// }, + +// // 选择业户 +// selectPayer({ commit }, payer) { +// commit('SET_CURRENT_PAYER', payer); +// }, +}; + +const getters = { + // 当前选择的业户ID + currentPayerId(state) { + return state.currentPayer ? state.currentPayer.id : null; + }, + // 当前选择的业户名称 + currentPayerName(state) { + return state.currentPayer ? state.currentPayer.name : ''; + }, + // 是否已选择业户 + hasSelectedPayer(state) { + return !!state.currentPayer; + }, +}; + +export default { + namespaced: true, + state, + mutations, + actions, + getters, +}; \ No newline at end of file diff --git a/h5/src/utils/request.js b/h5/src/utils/request.js new file mode 100644 index 0000000..9f69d01 --- /dev/null +++ b/h5/src/utils/request.js @@ -0,0 +1,164 @@ +import axios from 'axios'; +import { Toast } from 'vant'; +import qs from 'qs'; +import store from '@/store'; + +// 创建axios实例 +const service = axios.create({ + baseURL: 'http://192.168.137.45:8080', + timeout: 30000, + headers: { + 'Content-Type': 'application/json;charset=utf-8', + }, +}); + +// 请求拦截器 +service.interceptors.request.use( + (config) => { + // 显示loading,除非请求配置中指定了不显示 + if (config.showLoading !== false) { + store.dispatch('setLoading', true); + } + + // 获取token + const token = localStorage.getItem('token'); + if (token) { + config.headers.Authorization = `Bearer ${token}`; + } + + // 如果有选择业户,则在请求头中带上业户ID + const currentPayerId = store.getters['user/currentPayerId']; + if (currentPayerId) { + config.headers['X-Payer-Id'] = currentPayerId; + } + + // 处理GET请求参数 + if (config.method === 'get' && config.params) { + config.paramsSerializer = (params) => { + return qs.stringify(params, { arrayFormat: 'repeat' }); + }; + } + + return config; + }, + (error) => { + // 隐藏loading + store.dispatch('setLoading', false); + return Promise.reject(error); + } +); + +// 响应拦截器 +service.interceptors.response.use( + (response) => { + // 隐藏loading + store.dispatch('setLoading', false); + + // 处理二进制数据 + if (response.config.responseType === 'blob') { + return response; + } + + const res = response.data; + + // 判断是否成功 + if (res.code === '0000000000000000') { + return res; + } + + // 处理业务错误 + if (res.code === 'UNAUTHORIZED') { + // 未登录,跳转到登录页 + Toast.fail('用户未登录或登录已过期'); + localStorage.removeItem('token'); + setTimeout(() => { + window.location.href = '/login'; + }, 1500); + } else { + // 其他业务错误 + Toast.fail(res.message || '请求失败'); + } + + return res; + }, + (error) => { + // 隐藏loading + store.dispatch('setLoading', false); + + let message = '请求失败'; + if (error.response) { + switch (error.response.status) { + case 401: + message = '用户未登录或登录已过期'; + localStorage.removeItem('token'); + setTimeout(() => { + window.location.href = '/login'; + }, 1500); + break; + case 403: + message = '拒绝访问'; + break; + case 404: + message = '请求地址错误'; + break; + case 500: + message = '服务器内部错误'; + break; + default: + message = `请求失败(${error.response.status})`; + } + } else if (error.message.includes('timeout')) { + message = '请求超时'; + } + + Toast.fail(message); + return Promise.reject(error); + } +); + +// 封装请求方法 +export const request = { + get(url, params, config = {}) { + return service({ + url, + method: 'get', + params, + ...config + }); + }, + post(url, data, config = {}) { + return service({ + url, + method: 'post', + data, + ...config + }); + }, + put(url, data, config = {}) { + return service({ + url, + method: 'put', + data, + ...config + }); + }, + delete(url, params, config = {}) { + return service({ + url, + method: 'delete', + params, + ...config + }); + }, + download(url, params, config = {}) { + return service({ + url, + method: 'get', + params, + responseType: 'blob', + ...config + }); + }, +}; + +export default service; \ No newline at end of file diff --git a/h5/src/views/payment/BillDetail.vue b/h5/src/views/payment/BillDetail.vue new file mode 100644 index 0000000..085640f --- /dev/null +++ b/h5/src/views/payment/BillDetail.vue @@ -0,0 +1,236 @@ + + + + + \ No newline at end of file diff --git a/h5/src/views/payment/EnterprisePay.vue b/h5/src/views/payment/EnterprisePay.vue new file mode 100644 index 0000000..97b35db --- /dev/null +++ b/h5/src/views/payment/EnterprisePay.vue @@ -0,0 +1,296 @@ + + + + + \ No newline at end of file diff --git a/h5/src/views/payment/Index.vue b/h5/src/views/payment/Index.vue new file mode 100644 index 0000000..4f13720 --- /dev/null +++ b/h5/src/views/payment/Index.vue @@ -0,0 +1,619 @@ + + + + + \ No newline at end of file diff --git a/h5/src/views/payment/PayResult.vue b/h5/src/views/payment/PayResult.vue new file mode 100644 index 0000000..bd03b27 --- /dev/null +++ b/h5/src/views/payment/PayResult.vue @@ -0,0 +1,295 @@ + + + + + \ No newline at end of file diff --git a/h5/src/views/payment/PrepayBills.vue b/h5/src/views/payment/PrepayBills.vue new file mode 100644 index 0000000..270b43d --- /dev/null +++ b/h5/src/views/payment/PrepayBills.vue @@ -0,0 +1,602 @@ + + + + + \ No newline at end of file diff --git a/h5/src/views/payment/RecordDetail.vue b/h5/src/views/payment/RecordDetail.vue new file mode 100644 index 0000000..4070c20 --- /dev/null +++ b/h5/src/views/payment/RecordDetail.vue @@ -0,0 +1,286 @@ + + + + + \ No newline at end of file diff --git a/h5/src/views/payment/Records.vue b/h5/src/views/payment/Records.vue new file mode 100644 index 0000000..2f619ed --- /dev/null +++ b/h5/src/views/payment/Records.vue @@ -0,0 +1,378 @@ + + + + + \ No newline at end of file diff --git a/h5/vue.config.js b/h5/vue.config.js new file mode 100644 index 0000000..6398338 --- /dev/null +++ b/h5/vue.config.js @@ -0,0 +1,71 @@ +const { defineConfig } = require('@vue/cli-service'); + +module.exports = defineConfig({ + // 部署应用包时的基本 URL + publicPath: process.env.NODE_ENV === 'production' ? '/' : '/', + + // 当运行 vue-cli-service build 时生成的生产环境构建文件的目录 + outputDir: 'dist', + + // 放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录 + assetsDir: 'static', + + // 指定生成的 index.html 的输出路径 (相对于 outputDir) + indexPath: 'index.html', + + // 默认情况下,生成的静态资源在它们的文件名中包含了 hash 以便更好的控制缓存 + filenameHashing: true, + + // 是否在开发环境下通过 eslint-loader 在每次保存时 lint 代码 + lintOnSave: process.env.NODE_ENV !== 'production', + + // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建 + productionSourceMap: false, + + // 开发服务器配置 + devServer: { + host: '0.0.0.0', + port: 8080, + open: true, + // proxy: { + // // 配置跨域 + // '/': { + // target: 'http://192.168.137.45:8080', + // changeOrigin: true, + // pathRewrite: { + // '^/api': '' + // } + // } + // } + }, + + // CSS相关配置 + css: { + // 是否使用css分离插件 ExtractTextPlugin + extract: process.env.NODE_ENV === 'production', + // 开启 CSS source maps? + sourceMap: false, + // css预设器配置项 + loaderOptions: { + sass: { + // 全局引入变量和 mixin + additionalData: ` + @import "@/assets/styles/variables.scss"; + ` + } + } + }, + + // webpack配置 + configureWebpack: { + // 配置 webpack 压缩 + optimization: { + minimize: process.env.NODE_ENV === 'production' + } + }, + + // 第三方插件配置 + pluginOptions: { + // ... + } +}); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..c496ed7 --- /dev/null +++ b/package.json @@ -0,0 +1,10 @@ +{ + "dependencies": { + "element-china-area-data": "^6.1.0", + "html2canvas": "^1.4.1", + "mammoth": "^1.9.0", + "pdf-lib": "^1.17.1", + "pdfjs-dist": "^5.1.91", + "qrcode.vue": "^3.6.0" + } +} diff --git a/pc/.env.development b/pc/.env.development new file mode 100644 index 0000000..2754fd2 --- /dev/null +++ b/pc/.env.development @@ -0,0 +1,4 @@ +NODE_ENV = 'development' + +# 开发环境API地址 +VUE_APP_BASE_API = http://192.168.137.45:8080 \ No newline at end of file diff --git a/pc/.env.production b/pc/.env.production new file mode 100644 index 0000000..6465c6f --- /dev/null +++ b/pc/.env.production @@ -0,0 +1,4 @@ +NODE_ENV = 'production' + +# 生产环境API地址 +VUE_APP_BASE_API = http://192.168.137.3:8080/api \ No newline at end of file diff --git a/pc/.gitignore b/pc/.gitignore new file mode 100644 index 0000000..f71b978 --- /dev/null +++ b/pc/.gitignore @@ -0,0 +1,10 @@ +node_modules/ +.DS_Store +.idea/ +.vscode/ +.env +.env.local + + +package-lock.json +yarn.lock diff --git a/pc/package.json b/pc/package.json new file mode 100644 index 0000000..19dea53 --- /dev/null +++ b/pc/package.json @@ -0,0 +1,81 @@ +{ + "name": "yoaf-web", + "version": "1.1.2", + "description": "智慧教育平台", + "author": "front-end", + "license": "MIT", + "scripts": { + "dev": "vue-cli-service serve", + "build:prod": "vue-cli-service build", + "build:stage": "vue-cli-service build --mode staging", + "preview": "node build/index.js --preview" + }, + "keywords": [ + "vue", + "admin", + "dashboard", + "element-ui", + "boilerplate", + "admin-template", + "management-system" + ], + "dependencies": { + "@riophae/vue-treeselect": "^0.4.0", + "axios": "0.24.0", + "clipboard": "2.0.8", + "core-js": "3.19.1", + "dayjs": "^1.11.10", + "echarts": "4.9.0", + "element-ui": "^2.15.6", + "file-saver": "2.0.5", + "fuse.js": "6.4.3", + "highlight.js": "9.18.5", + "html2canvas": "^1.4.1", + "js-beautify": "1.13.0", + "js-cookie": "3.0.1", + "jszip": "^3.10.1", + "moment": "^2.30.1", + "nprogress": "0.2.0", + "qrcode": "^1.5.3", + "qrcode.vue": "^3.6.0", + "quill": "1.3.7", + "screenfull": "5.0.2", + "sm-crypto": "^0.3.12", + "sortablejs": "1.10.2", + "tui-image-editor": "^3.15.3", + "vue": "^2.7.14", + "vue-count-to": "1.0.13", + "vue-cropper": "0.5.5", + "vue-meta": "2.4.0", + "vue-router": "3.4.9", + "vuedraggable": "^2.24.3", + "vuex": "3.6.0", + "xlsx": "^0.18.5", + "element-china-area-data": "^6.1.0", + "mammoth": "^1.9.0" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "4.4.6", + "@vue/cli-service": "4.4.6", + "babel-loader": "^10.0.0", + "babel-plugin-dynamic-import-node": "2.3.3", + "chalk": "4.1.0", + "compression-webpack-plugin": "5.0.2", + "connect": "3.6.6", + "mockjs": "^1.0.1-beta3", + "runjs": "4.4.2", + "sass": "1.32.13", + "sass-loader": "10.1.1", + "script-ext-html-webpack-plugin": "2.1.5", + "svg-sprite-loader": "5.1.1", + "vue-template-compiler": "2.6.14" + }, + "engines": { + "node": ">=8.9", + "npm": ">= 3.0.0" + }, + "browserslist": [ + ">1%", + "last 2 versions" + ] +} diff --git a/pc/public.zip b/pc/public.zip new file mode 100644 index 0000000..028483f Binary files /dev/null and b/pc/public.zip differ diff --git a/pc/public/index.html b/pc/public/index.html new file mode 100644 index 0000000..a66625c --- /dev/null +++ b/pc/public/index.html @@ -0,0 +1,17 @@ + + + + + + + + 智慧教育平台 + + + +
+ + + \ No newline at end of file diff --git a/pc/src/App.vue b/pc/src/App.vue new file mode 100644 index 0000000..4194d3c --- /dev/null +++ b/pc/src/App.vue @@ -0,0 +1,20 @@ + + + + + \ No newline at end of file diff --git a/pc/src/api/asset/classification.js b/pc/src/api/asset/classification.js new file mode 100644 index 0000000..eb64c9e --- /dev/null +++ b/pc/src/api/asset/classification.js @@ -0,0 +1,110 @@ +import request from '@/utils/request' + +// 查询资产分类列表 +export function listClassification(query) { + return request({ + url: '/asset/classifications/list', + method: 'get', + params: query + }) +} + +// 查询资产分类详情 +export function getClassification(id) { + return request({ + url: '/asset/classifications/' + id, + method: 'get' + }) +} + +// 新增资产分类 +export function addClassification(data) { + return request({ + url: '/asset/classifications/create', + method: 'post', + data: data + }) +} + +// 修改资产分类 +export function updateClassification(data) { + return request({ + url: '/asset/classifications/update/' + data.id, + method: 'post', + data: data + }) +} + +// 删除资产分类 +export function delClassification(id, lastModUserId) { + return request({ + url: '/asset/classifications/delete/' + id, + method: 'post', + params: lastModUserId ? { lastModUserId } : {} + }) +} + +// 禁用资产分类 +export function disableClassification(id, lastModUserId) { + return request({ + url: '/asset/classifications/' + id + '/status/disable', + method: 'post', + params: lastModUserId ? { lastModUserId } : {} + }) +} + +// 启用资产分类 +export function enableClassification(id, lastModUserId) { + return request({ + url: '/asset/classifications/' + id + '/status/enable', + method: 'post', + params: lastModUserId ? { lastModUserId } : {} + }) +} + +// 批量删除资产分类 +export function delClassificationBatch(ids, lastModUserId) { + return request({ + url: '/asset/classifications/deleteBatch', + method: 'post', + data: ids, + params: lastModUserId ? { lastModUserId } : {} + }) +} + +// 获取资产分类树形结构 +export function getClassificationTree(query) { + return request({ + url: '/asset/classifications/tree', + method: 'get', + params: query + }) +} + +// 根据父ID查询子分类 +export function getChildClassifications(parentId, query) { + + return request({ + url: '/asset/classifications/children/' + parentId, + method: 'get', + params: query + }) +} + +// 检查分类是否被使用 +export function checkClassificationInUse(id) { + return request({ + url: '/asset/classifications/' + id + '/check', + method: 'get' + }) +} + +// 导出资产分类 +export function exportClassification(query) { + + return request({ + url: '/asset/classifications/export', + method: 'get', + params: query + }) +} \ No newline at end of file diff --git a/pc/src/api/asset/inventory.js b/pc/src/api/asset/inventory.js new file mode 100644 index 0000000..848a80d --- /dev/null +++ b/pc/src/api/asset/inventory.js @@ -0,0 +1,136 @@ +import request from '@/utils/request' + +// 获取资产列表 +export function listAssets(query) { + return request({ + url: '/asset/list', + method: 'get', + params: query + }) +} + +// 获取资产详情 +export function getAsset(assetCode) { + return request({ + url: `/asset/${assetCode}`, + method: 'get', + }) +} + +// 新增资产 +export function addAsset(data) { + return request({ + url: '/asset/create', + method: 'post', + data: data + }) +} + +// 修改资产 +export function updateAsset(data) { + return request({ + url: `/asset/update/${data.assetCode}`, + method: 'post', + data: data + }) +} + +// 删除资产 +export function deleteAsset(assetCode) { + return request({ + url: '/asset/delete', + method: 'post', + params: { assetCode } + }) +} + +// 批量删除资产 +export function deleteAssets(assetCodes) { + return request({ + url: '/asset/batch/delete', + method: 'post', + data: { assetCodes } + }) +} + +// 导出资产 +export function exportAsset(query) { + return request({ + url: '/asset/export', + method: 'get', + params: query, + responseType: 'blob' + }) +} + +// 下载资产导入模板 +export function downloadTemplate() { + return request({ + url: '/asset/template/download', + method: 'get', + responseType: 'blob' + }) +} + +// 获取资产位置树 +export function listAssetLocationTree() { + return request({ + url: '/asset/location/tree', + method: 'get' + }) +} + +// 获取公司列表 +export function listCompanies() { + return request({ + url: '/admin/company/getAllCompanyDetails', + method: 'get' + }) +} + +// 获取用户列表 +export function listUsers() { + return request({ + url: '/v1/member/list', + method: 'get', + }) +} + +// 上传资产图片 +export function uploadAssetImage(data) { + return request({ + url: '/asset/upload/image', + method: 'post', + data: data + }) +} + +/** + * 批量打印资产标签 + * @param {Array} assetCodes 资产编码数组 + * @returns {Object} 请求结果 + */ +export function printAssetLabels(assetCodes) { + return request({ + url: '/asset/print', + method: 'post', + data: assetCodes + }) +} + +// 检查资产编码是否存在 +export function checkAssetCode(code) { + return request({ + url: '/asset/check/code', + method: 'get', + params: { code } + }) +} + +// 获取标签配置 +export function getLabelConfig() { + return request({ + url: '/asset/label', + method: 'get' + }) +} \ No newline at end of file diff --git a/pc/src/api/asset/label.js b/pc/src/api/asset/label.js new file mode 100644 index 0000000..0971a09 --- /dev/null +++ b/pc/src/api/asset/label.js @@ -0,0 +1,110 @@ +import request from '@/utils/request' + +// 查询资产标签列表 +export function listLabelTemplates(query) { + return request({ + url: '/asset/label/list', + method: 'get', + params: query + }) +} + +// 获取标签模板详情 +export function getLabelTemplate(id) { + return request({ + url: '/asset/label/template/' + id, + method: 'get' + }) +} + +// 新增资产标签 +export function addLabelTemplate(data) { + return request({ + url: '/asset/label/create', + method: 'post', + data: data + }) +} + +// 修改资产标签 +export function updateLabelTemplate(id, data) { + return request({ + url: '/asset/label/update' + id, + method: 'post', + data: data + }) +} + +// 删除标签模板 +export function deleteLabelTemplate(id) { + return request({ + url: '/asset/label/template/' + id, + method: 'post' + }) +} + +// 设置默认模板 +export function setDefaultTemplate(id) { + return request({ + url: '/asset/label/template/default/' + id, + method: 'post' + }) +} + +// 获取可用的标签字段 +export function getLabelFields() { + const fieldData = [ + { id: 1, name: '资产名称' }, + { id: 2, name: '资产分类' }, + { id: 3, name: '资产编码' }, + { id: 4, name: '资产位置' }, + { id: 5, name: '品牌' }, + { id: 6, name: '型号' }, + { id: 7, name: '设备序列号' }, + { id: 8, name: '管理员' }, + { id: 9, name: '保养到期时间' }, + { id: 10, name: '保养说明' }, + { id: 11, name: '使用部门' } + ]; + + return Promise.resolve({ + code: '0000000000000000', + msg: 'success', + data: fieldData + }); +} + +// 获取字段对应的示例值 +export function getFieldSampleValues() { + return { + '1': 'ThinkPad笔记本', + '2': '电脑/笔记本电脑', + '3': 'ASSET-001', + '4': '研发部-A区', + '5': 'Lenovo', + '6': 'X1 Carbon', + '7': 'SN12345678', + '8': '张三', + '9': '2024-12-31', + '10': '每季度保养一次', + '11': '研发部' + }; +} + +// 打印标签预览 +export function previewLabel(data) { + return request({ + url: '/asset/label/preview', + method: 'post', + data: data + }) +} + +// 打印标签 +export function printLabel(data) { + return request({ + url: '/asset/label/print', + method: 'post', + data: data + }) +} \ No newline at end of file diff --git a/pc/src/api/asset/location.js b/pc/src/api/asset/location.js new file mode 100644 index 0000000..d36e242 --- /dev/null +++ b/pc/src/api/asset/location.js @@ -0,0 +1,120 @@ +import request from '@/utils/request' + +// 查询资产位置列表 +export function listLocation(query) { + return request({ + url: '/asset/locations/list', + method: 'get', + params: query + }) +} + +// 查询资产位置详情 +export function getLocation(id) { + return request({ + url: '/asset/locations/' + id, + method: 'get' + }) +} + +// 新增资产位置 +export function addLocation(data) { + return request({ + url: '/asset/locations/create', + method: 'post', + data: data + }) +} + +// 修改资产位置 +export function updateLocation(data) { + return request({ + url: '/asset/locations/update/' + data.id, + method: 'post', + data: data + }) +} + +// 删除资产位置 +export function delLocation(id, lastModUserId) { + return request({ + url: '/asset/locations/delete/' + id, + method: 'post', + params: lastModUserId ? { lastModUserId } : {} + }) +} + +// 禁用资产位置 +export function disableLocation(id, lastModUserId) { + return request({ + url: '/asset/locations/' + id + '/status/disable', + method: 'post', + params: lastModUserId ? { lastModUserId } : {} + }) +} + +// 启用资产位置 +export function enableLocation(id, lastModUserId) { + return request({ + url: '/asset/locations/' + id + '/status/enable', + method: 'post', + params: lastModUserId ? { lastModUserId } : {} + }) +} + +// 批量删除资产位置 +export function delLocationBatch(ids, lastModUserId) { + return request({ + url: '/asset/locations/batch/delete', + method: 'post', + data: ids, + params: lastModUserId ? { lastModUserId } : {} + }) +} + +// 获取资产位置树形结构 +export function getLocationTree(query) { + return request({ + url: '/asset/locations/tree', + method: 'get', + params: query + }) +} + +// 根据父ID查询子位置 +export function getChildLocations(parentId, query) { + return request({ + url: '/asset/locations/children/' + parentId, + method: 'get', + params: query + }) +} + +// 检查位置是否被使用 +export function checkLocationInUse(id) { + return request({ + url: '/asset/locations/' + id + '/check', + method: 'get' + }) +} + +// 检查编码唯一性 +export function checkLocationCode(id, locationCode) { + return request({ + url: '/asset/locations/check/code', + method: 'get', + params: { + id: id, + locationCode: locationCode + } + }) +} + +// 导出资产位置 +export function exportLocation(query) { + return request({ + url: '/asset/locations/export', + method: 'get', + params: query + }) +} \ No newline at end of file diff --git a/pc/src/api/bak/merchant/index.js b/pc/src/api/bak/merchant/index.js new file mode 100644 index 0000000..68df39a --- /dev/null +++ b/pc/src/api/bak/merchant/index.js @@ -0,0 +1,7 @@ +// 导出所有子模块 +export * from './lead' + +// 未来可以添加其他子模块,如: +// export * from './team' +// export * from './personnel' +// 等等 \ No newline at end of file diff --git a/pc/src/api/bak/merchant/lead.js b/pc/src/api/bak/merchant/lead.js new file mode 100644 index 0000000..67f447c --- /dev/null +++ b/pc/src/api/bak/merchant/lead.js @@ -0,0 +1,151 @@ +import request from '@/utils/request' + +// 线索状态API +export function getLeadStatusList() { + return request({ + url: '/bizLead/status/list', + method: 'get' + }) +} + +export function getLeadStatusDetail(id) { + return request({ + url: `/bizLead/status/${id}`, + method: 'get' + }) +} + +export function addLeadStatus(data) { + return request({ + url: '/bizLead/status', + method: 'post', + data + }) +} + +export function updateLeadStatus(data) { + return request({ + url: '/bizLead/status', + method: 'put', + data + }) +} + +export function deleteLeadStatus(id, userId) { + return request({ + url: `/bizLead/status/${id}`, + method: 'delete', + params: { userId } + }) +} + +export function checkLeadStatusName(statusName) { + return request({ + url: '/bizLead/status/checkName', + method: 'get', + params: { statusName } + }) +} + +// 线索管理API +export function getLeadList(params) { + return request({ + url: '/bizLead/list', + method: 'get', + params + }) +} + +export function getMyLeadList(params) { + return request({ + url: '/bizLead/myLeads', + method: 'get', + params + }) +} + +export function getAllLeadList(params) { + return request({ + url: '/bizLead/allLeads', + method: 'get', + params + }) +} + +export function getPublicLeadList(params) { + return request({ + url: '/bizLead/publicLeads', + method: 'get', + params + }) +} + +export function getLeadDetail(id) { + return request({ + url: `/bizLead/${id}`, + method: 'get' + }) +} + +export function addLead(data) { + return request({ + url: '/bizLead', + method: 'post', + data + }) +} + +export function updateLead(data) { + return request({ + url: '/bizLead', + method: 'put', + data + }) +} + +export function changeLeadStatus(id, statusId, userId) { + return request({ + url: `/bizLead/${id}/status`, + method: 'put', + params: { statusId, userId } + }) +} + +export function changeLeadPersonnel(id, personnelId, userId) { + return request({ + url: `/bizLead/${id}/personnel`, + method: 'put', + params: { personnelId, userId } + }) +} + +export function checkLeadPhone(phone) { + return request({ + url: '/bizLead/checkPhone', + method: 'get', + params: { phone } + }) +} + +export function convertLeadToIntention(id, userId) { + return request({ + url: `/bizLead/${id}/convert`, + method: 'post', + params: { userId } + }) +} + +export function deleteLead(id, userId) { + return request({ + url: `/bizLead/${id}`, + method: 'delete', + params: { userId } + }) +} + +export function getLeadFollowHistory(leadId) { + return request({ + url: `/bizLead/${leadId}/followHistory`, + method: 'get' + }) +} \ No newline at end of file diff --git a/pc/src/api/building.js b/pc/src/api/building.js new file mode 100644 index 0000000..872224a --- /dev/null +++ b/pc/src/api/building.js @@ -0,0 +1,140 @@ +import request from '@/utils/request' + +// 查询楼宇列表 +export function getBuildingList(query) { + return request({ + url: '/room/building/list', + method: 'get', + params: query + }) +} + +// 查询楼宇详细 +export function getBuildingDetail(id) { + return request({ + url: `/room/building/${id}`, + method: 'get' + }) +} + +// 新增楼宇 +export function addBuilding(data) { + // 处理字段名映射,确保前端驼峰命名与后端下划线命名正确对应 + const processedData = { + ...data, + buildingTags: data.buildingTags, + isHot: data.isHot, + imageUrl: data.buildingImage, + } + + // 删除undefined的属性 + Object.keys(processedData).forEach(key => { + if (processedData[key] === undefined) { + delete processedData[key] + } + }) + + return request({ + url: '/room/building/add', + method: 'post', + data: processedData + }) +} + +// 修改楼宇 +export function updateBuilding(data) { + // 处理字段名映射,确保前端驼峰命名与后端下划线命名正确对应 + const processedData = { + ...data, + buildingTags: data.buildingTags, + isHot: data.isHot, + imageUrl: data.buildingImage + } + + // 删除undefined的属性 + Object.keys(processedData).forEach(key => { + if (processedData[key] === undefined) { + delete processedData[key] + } + }) + + return request({ + url: '/room/building/edit', + method: 'post', + data: processedData + }) +} + +// 删除楼宇 +export function deleteBuilding(ids) { + return request({ + url: `/room/building/remove/${ids}`, + method: 'get' + }) +} + +// 获取楼宇统计信息 +export function getBuildingStatistics(id) { + return request({ + url: `/room/building/${id}/statistics`, + method: 'get' + }) +} + +// 查询楼层列表 +export function getFloorList(query) { + return request({ + url: `/room/floor/list/${query}`, + method: 'get' + }) +} + +// 获取楼层详情 +export function getFloorDetail(id) { + return request({ + url: `/room/floor/${id}`, + method: 'get' + }) +} + +// 新增楼层 +export function addFloor(data) { + return request({ + url: '/room/floor/add', + method: 'post', + data: data + }) +} + +// 修改楼层 +export function updateFloor(data) { + return request({ + url: '/room/floor/edit', + method: 'post', + data: data + }) +} + +// 删除楼层 +export function deleteFloor(ids) { + return request({ + url: `/room/floor/remove/${ids}`, + method: 'get' + }) +} + +// 根据楼宇ID获取楼层列表 +export function getFloorListByBuilding(buildingId) { + return request({ + url: `/room/floor/building/${buildingId}`, + method: 'get' + }) +} + +// 收支账号管理 +export function getAllAccounts() { + return request({ + url: `/admin/account/getAllAccounts`, + method: 'get' + }) +} \ No newline at end of file diff --git a/pc/src/api/finance.js b/pc/src/api/finance.js new file mode 100644 index 0000000..d180721 --- /dev/null +++ b/pc/src/api/finance.js @@ -0,0 +1,925 @@ +import request from '@/utils/request' + +// 费用分类管理接口 +export function getFeeCategories(query) { + return request({ + url: '/finance/category/page', + method: 'get', + params: query + }) +} + +export function getAllFeeCategories() { + return request({ + url: '/finance/category/list', + method: 'get' + }) +} + +export function getFeeCategory(id) { + return request({ + url: `/finance/category/${id}`, + method: 'get' + }) +} + +export function addFeeCategory(data) { + return request({ + url: '/finance/category', + method: 'post', + data + }) +} + +export function updateFeeCategory(id, data) { + return request({ + url: `/finance/category/${id}`, + method: 'put', + data + }) +} + +export function deleteFeeCategory(id) { + return request({ + url: `/finance/category/${id}`, + method: 'delete' + }) +} + +// 费用类型管理接口 +export function getFeeTypes(query) { + return request({ + url: '/finance/type/page', + method: 'get', + params: query + }) +} + +export function getFeeTypesByCategory(categoryId) { + return request({ + url: `/finance/type/list/${categoryId}`, + method: 'get' + }) +} + +export function getFeeType(id) { + return request({ + url: `/finance/type/${id}`, + method: 'get' + }) +} + +export function addFeeType(data) { + return request({ + url: '/finance/type', + method: 'post', + data + }) +} + +export function updateFeeType(id, data) { + return request({ + url: `/finance/type/${id}`, + method: 'put', + data + }) +} + +export function deleteFeeType(id) { + return request({ + url: `/finance/type/${id}`, + method: 'delete' + }) +} + + +// 收据编号规则相关接口 +export function listReceiptRule(params) { + return request({ + url: '/receipt/number-rule/page', + method: 'get', + params + }) +} + +export function addReceiptRule(data) { + return request({ + url: '/receipt/number-rule', + method: 'post', + data + }) +} + +export function deleteReceiptRule(id) { + return request({ + url: `/receipt/number-rule/${id}`, + method: 'delete' + }) +} + +export function getNextReceiptNumber(ruleId) { + return request({ + url: `/receipt/number/next/${ruleId}`, + method: 'get' + }) +} + +export function getBatchReceiptNumbers(ruleId, count) { + return request({ + url: `/receipt/numbers/${ruleId}/${count}`, + method: 'get' + }) +} + +// 收据模板相关接口 +export function getReceiptTemplateList(params) { + return request({ + url: '/receipt/template/page', + method: 'get', + params + }) +} + +export function addReceiptTemplate(data) { + return request({ + url: '/receipt/template', + method: 'post', + data + }) +} + +export function updateReceiptTemplate(id, data) { + return request({ + url: `/receipt/template/${id}`, + method: 'put', + data + }) +} + +export function deleteReceiptTemplate(id) { + return request({ + url: `/receipt/template/${id}`, + method: 'delete' + }) +} + +export function previewReceiptTemplate(id) { + return request({ + url: `/receipt/template/preview/${id}`, + method: 'get', + responseType: 'blob' + }) +} + +export function downloadReceiptTemplate(id) { + return request({ + url: `/receipt/template/download/${id}`, + method: 'get', + responseType: 'blob' + }) +} + +export function downloadExampleTemplate() { + return request({ + url: '/receipt/template/download-example', + method: 'get', + responseType: 'blob' + }) +} + +export function getReceiptKeywords() { + return request({ + url: '/receipt/template/keywords', + method: 'get' + }) +} + +export function checkTemplateName(params) { + return request({ + url: '/receipt/template/check-name', + method: 'get', + params + }) +} + +// 收款方信息相关接口 +export function getPayeeInfo(params) { + if (typeof params === 'object') { + // 查询列表 + return request({ + url: '/receipt/payee/page', + method: 'get', + params + }) + } else { + // 查询详情 + return request({ + url: `/receipt/payee/${params}`, + method: 'get' + }) + } +} + +export function addPayeeInfo(data) { + return request({ + url: '/receipt/payee', + method: 'post', + data + }) +} + +export function updatePayeeInfo(id, data) { + return request({ + url: `/receipt/payee/${id}`, + method: 'put', + data + }) +} + +export function deletePayeeInfo(id) { + return request({ + url: `/receipt/payee/${id}`, + method: 'delete' + }) +} + +// 项目列表 +export function getProjectList() { + return request({ + url: '/project/list', + method: 'get' + }) +} + +// 获取楼宇列表 +export function getBuildingList(projectId) { + return request({ + url: `/business/building/list/${projectId}`, + method: 'get' + }) +} + +/* 收费标准相关接口 */ + +// 分页查询收费标准列表 +export function getChargingStandardPage(query) { + return request({ + url: '/finance/charging-standard/page', + method: 'get', + params: query + }) +} + +// 根据ID查询收费标准详情 +export function getChargingStandardById(id) { + return request({ + url: `/finance/charging-standard/${id}`, + method: 'get' + }) +} + +// 新增收费标准 +export function addChargingStandard(data) { + return request({ + url: '/finance/charging-standard', + method: 'post', + data: data + }) +} + +// 修改收费标准 +export function updateChargingStandard(data) { + return request({ + url: '/finance/charging-standard', + method: 'put', + data: data + }) +} + +// 删除收费标准 +export function deleteChargingStandard(id) { + return request({ + url: `/finance/charging-standard/${id}`, + method: 'delete' + }) +} + +// 更新收费标准状态(立即失效) +export function updateChargingStandardStatus(id) { + return request({ + url: `/finance/charging-standard/${id}/updateStatus`, + method: 'put' + }) +} + +// 检查收费标准名称是否存在 +export function checkChargingStandardName(standardName, id) { + return request({ + url: '/finance/charging-standard/check-name', + method: 'get', + params: { standardName, id } + }) +} + +// 根据状态查询收费标准列表 +export function getChargingStandardListByStatus(status) { + return request({ + url: '/finance/charging-standard/list-by-status', + method: 'get', + params: { status } + }) +} + +// 获取费用类型树 +export function getFeeTypeTree(params) { + return request({ + url: '/feeForeign/categories', + method: 'get', + params + }) +} + +// 预览账单 +export function previewBill(data) { + return request({ + url: '/finance/charging-standard/bill/preview', + method: 'post', + headers: { + 'Content-Type': 'application/json' + }, + data + }) +} + +// 生成账单 +export function generateBill(data) { + return request({ + url: '/finance/charging-standard/bill/generate', + method: 'post', + headers: { + 'Content-Type': 'application/json' + }, + data + }) +} + +/** + * 分页查询账单-收费标准关联表数据 + * @param {Object} data - 查询参数 + * @returns {Promise} - 返回Promise对象 + */ +export function getBillChargingStandardRelPage(data) { + return request({ + url: '/finance/bill-charging-standard-rel/page', + method: 'post', + data + }) +} + +/** + * 获取特定标准ID的绑定房间账单列表 + * @param {string} standardId 收费标准ID + */ +export function getBillsByStandardId(standardId) { + return request({ + url: `/finance/bill-charging-standard-rel/${standardId}/bills`, + method: 'get' + }) +} + +// 账单管理接口 +export function addBill(data) { + return request({ + url: '/bill/add', + method: 'post', + data + }) +} + +export function getBillList(data) { + return request({ + url: '/bill/list', + method: 'post', + data + }) +} + +export function getBillDetail(billId) { + return request({ + url: `/bill/detail/${billId}`, + method: 'get' + }) +} + +export function uploadBillAttachment(billId, file) { + const formData = new FormData() + formData.append('billId', billId) + formData.append('file', file) + return request({ + url: '/bill/upload-attachment', + method: 'post', + data: formData, + headers: { + 'Content-Type': 'multipart/form-data' + } + }) +} + +// 账单附件删除 +export function deleteBillAttachment(attachmentId) { + return request({ + url: `/bill/attachment/delete/${attachmentId}`, + method: 'get' + }) +} + +export function getBillAttachmentList(billId) { + return request({ + url: `/bill/attachment/list/${billId}`, + method: 'get' + }) +} + +export function exportBillList(data) { + return request({ + url: '/bill/export', + method: 'post', + data, + responseType: 'blob' + }) +} + +// 收支流水相关接口 +export function getTransactionList(params) { + return request({ + url: '/finance/transaction/page', + method: 'get', + params + }) +} + +export function getTransactionDetail(id) { + return request({ + url: `/finance/transaction/${id}`, + method: 'get' + }) +} + +export function addTransaction(data) { + return request({ + url: '/finance/transaction', + method: 'post', + data + }) +} + +export function updateTransaction(data) { + return request({ + url: '/finance/transaction', + method: 'put', + data + }) +} + +export function exportTransactionList(params) { + return request({ + url: '/finance/transaction/export', + method: 'get', + params, + responseType: 'blob' + }) +} + +export function getTransactionAttachments(transactionId) { + return request({ + url: `/finance/transaction/${transactionId}`, + method: 'get' + }) +} + +export function uploadTransactionAttachment(transactionId, file) { + const formData = new FormData() + formData.append('transactionId', transactionId) + formData.append('userId', localStorage.getItem('userId') || '') + formData.append('userName', localStorage.getItem('userName') || '') + formData.append('file', file) + + return request({ + url: '/finance/transaction/attachment', + method: 'post', + data: formData, + headers: { + 'Content-Type': 'multipart/form-data' + } + }) +} + +export function deleteTransactionAttachment(attachmentId) { + return request({ + url: `/finance/transaction/attachment/file/${attachmentId}`, + method: 'delete' + }) +} + +export function previewAttachment(attachmentId) { + return request({ + url: `/finance/transaction/attachment/preview/file/${attachmentId}`, + method: 'get', + responseType: 'blob' + }) +} + +export function previewAttachmentByFileId(fileId) { + return request({ + url: `/finance/transaction/attachment/preview/file/${fileId}`, + method: 'get', + responseType: 'blob' + }) +} + +export function downloadAttachment(fileId, fileName) { + return request({ + url: `/finance/transaction/attachment/download/${fileId}`, + method: 'get', + params: { fileName }, + responseType: 'blob' + }) +} + +export function deleteAttachmentByFileId(fileId) { + return request({ + url: `/finance/transaction/attachment/file/${fileId}`, + method: 'delete', + params: { + userId: localStorage.getItem('userId') || '' + } + }) +} + +export function addTransactionOperation(data) { + return request({ + url: '/finance/transaction/operation', + method: 'post', + data + }) +} + +export function getTransactionOperationLogs(transactionId, query) { + return request({ + url: `/finance/transaction/${transactionId}`, + method: 'get' + }) +} + +// 获取所有收支账户 +export function getAllFinanceAccounts() { + return request({ + url: '/finance/account/list', + method: 'get' + }) +} + +// 获取流水账户级联选项 +export function getAccountCascaderOptions() { + return request({ + url: '/finance/account/cascader', + method: 'get' + }) +} + +// 账单调整相关接口 + +// 添加账单调整(按金额或按比例) +export function addBillAdjustment(data) { + return request({ + url: '/v1/bill-adjustments', + method: 'post', + data + }) +} + +// 调整账单滞纳金专用接口 +export function adjustLateFee(data) { + return request({ + url: '/v1/late-fees/adjust', + method: 'post', + data + }) +} + +// 结算账单滞纳金接口 +export function settleLateFee(data) { + return request({ + url: '/v1/late-fees/settle', + method: 'post', + data + }) +} + +// 作废账单调整 +export function voidBillAdjustment(data) { + return request({ + url: '/v1/bill-adjustments/void', + method: 'put', + data + }) +} + +// 分页查询账单调整记录 +export function getBillAdjustmentList(params) { + return request({ + url: '/v1/bill-adjustments', + method: 'get', + params + }) +} + +// 获取账单调整详情 +export function getBillAdjustmentDetail(id) { + return request({ + url: `/v1/bill-adjustments/${id}`, + method: 'get' + }) +} + +// 上传账单调整附件 +export function uploadBillAdjustmentAttachment(id, file) { + const formData = new FormData() + formData.append('file', file) + return request({ + url: `/v1/bill-adjustments/${id}/attachments`, + method: 'post', + data: formData, + headers: { + 'Content-Type': 'multipart/form-data' + } + }) +} + +// 删除账单调整附件 +export function deleteBillAdjustmentAttachment(attachmentId) { + return request({ + url: `/v1/bill-adjustments/attachments/${attachmentId}`, + method: 'delete' + }) +} + +// 获取账单明细 +export function getBillDetailById(detailId) { + return request({ + url: `/v1/bill-details/${detailId}`, + method: 'get' + }) +} + +// 获取账单调整附件列表 +export function getBillAdjustmentAttachmentList(adjustmentId) { + return request({ + url: `/v1/bill-adjustments/attachments/view/${adjustmentId}`, + method: 'get' + }) +} + +// 获取账单操作记录 +export function getBillOperationRecords(billId, params) { + return request({ + url: `/v1/operation-records/list/${billId}`, + method: 'get', + params + }) +} + +// 账单支付相关接口 +// 提交账单支付 +export function submitBillPayment(data) { + return request({ + url: '/v1/bill-payments', + method: 'post', + data + }) +} + +// 分页查询支付记录 +export function getBillPaymentRecords(params) { + return request({ + url: '/v1/bill-payments', + method: 'get', + params + }) +} + +// 获取支付详情 +export function getBillPaymentDetail(id) { + return request({ + url: `/v1/bill-payments/${id}`, + method: 'get' + }) +} + +// 上传支付附件 +export function uploadBillPaymentAttachment(id, file) { + const formData = new FormData() + formData.append('file', file) + return request({ + url: `/v1/bill-payments/${id}/attachments`, + method: 'post', + data: formData, + headers: { + 'Content-Type': 'multipart/form-data' + } + }) +} + +// 删除支付附件 +export function deleteBillPaymentAttachment(attachmentId) { + return request({ + url: `/v1/bill-payments/attachments/${attachmentId}`, + method: 'delete' + }) +} + +// 收据记录相关接口 +export function getReceiptRecordPage(params) { + return request({ + url: '/finance/receipt/page', + method: 'get', + params + }) +} + +// 获取账单关联的收支流水列表 +export function getBillTransactionList(billId, params) { + return request({ + url: `/v1/bill/${billId}/transactions`, + method: 'get', + params + }) +} + +export function getReceiptRecordDetail(id) { + return request({ + url: `/finance/receipt/${id}`, + method: 'get' + }) +} + +export function voidReceipt(id) { + return request({ + url: `/finance/receipt/void/${id}`, + method: 'post' + }) +} + +export function generateReceipt(data) { + return request({ + url: '/finance/receipt/generate', + method: 'post', + data + }) +} + +export function previewReceipt(previewId) { + return request({ + url: `/finance/receipt/preview/${previewId}`, + method: 'get', + responseType: 'blob' + }) +} + +export function downloadReceipt(previewId) { + return request({ + url: `/finance/receipt/download-preview/${previewId}`, + method: 'get', + responseType: 'blob' + }) +} + +export function printReceipt(previewId) { + return request({ + url: `/finance/receipt/print/${previewId}`, + method: 'get', + responseType: 'blob' + }) +} + +export function downloadReceiptByFilename(receiptFileName) { + return request({ + url: '/finance/receipt/download-by-filename', + method: 'get', + params: { receiptFileName }, + responseType: 'blob' + }) +} + +export function previewReceiptByFilename(receiptFileName) { + return request({ + url: '/finance/receipt/preview-by-filename', + method: 'get', + params: { receiptFileName }, + responseType: 'blob' + }) +} + +export function printReceiptByFilename(receiptFileName) { + return request({ + url: '/finance/receipt/print-by-filename', + method: 'get', + params: { receiptFileName }, + responseType: 'blob' + }) +} + +// 关闭账单 +export function closeBill(data) { + return request({ + url: '/bill/close', + method: 'post', + data + }) +} + +// 获取可开据收据明细 +export function getReceiptDetails(billId) { + return request({ + url: '/receipt/details', + method: 'get', + params: { billId } + }) +} + +// 开具收据 +export function issueReceipt(data) { + return request({ + url: '/receipt/issue', + method: 'post', + data + }) +} + +// 分页查询收据记录 +export function getReceiptRecords(billId, params) { + return request({ + url: '/receipt/records', + method: 'get', + params: { billId, ...params } + }) +} + +// 获取收据详情 +export function getReceiptDetail(id) { + return request({ + url: '/receipt/detail', + method: 'get', + params: { id } + }) +} + +// 更新收据状态为已发出 +export function updateReceiptIssueStatus(id) { + return request({ + url: '/receipt/issue-status', + method: 'post', + data: { id } + }) +} + +// 作废收据 +export function voidReceiptById(id) { + return request({ + url: '/receipt/void', + method: 'post', + data: { id } + }) +} + +// 获取支付方式选项 +export function getPaymentMethodOptions() { + return request({ + url: '/receipt/payment-methods', + method: 'get' + }) +} + +// 获取收据状态选项 +export function getReceiptStatusOptions() { + return request({ + url: '/receipt/status-options', + method: 'get' + }) +} + +// 获取下一个收据编号 +export function getNextReceiptNumberByRuleId(ruleId) { + return request({ + url: `/receipt/number/next/${ruleId}`, + method: 'get' + }) +} + +// 批量获取收据编号 +export function getBatchReceiptNumbersByRuleId(ruleId, count) { + return request({ + url: `/receipt/numbers/${ruleId}/${count}`, + method: 'get' + }) +} \ No newline at end of file diff --git a/pc/src/api/inventory.js b/pc/src/api/inventory.js new file mode 100644 index 0000000..98b1e47 --- /dev/null +++ b/pc/src/api/inventory.js @@ -0,0 +1,29 @@ +import request from '@/utils/request' + +/** + * 导入库存 + * @param {Object} data 文件数据 + * @returns {Object} 请求结果 + */ +export function importInventory(data) { + return request({ + url: '/inventory/import', + method: 'post', + data: data, + headers: { + 'Content-Type': 'multipart/form-data' + } + }) +} + +/** + * 下载库存导入模板 + * @returns {Object} 请求结果 + */ +export function downloadInventoryTemplate() { + return request({ + url: '/inventory/template/download', + method: 'get', + responseType: 'blob' + }) +} \ No newline at end of file diff --git a/pc/src/api/merchant.js b/pc/src/api/merchant.js new file mode 100644 index 0000000..bcc6bcd --- /dev/null +++ b/pc/src/api/merchant.js @@ -0,0 +1,583 @@ +import request from '@/utils/request' + +// 招商团队相关API +export function getMerchantTeamList(params) { + return request({ + url: '/bizTeam/list', + method: 'get', + params + }) +} + +export function getMerchantTeamDetail(id) { + return request({ + url: `/bizTeam/${id}`, + method: 'get' + }) +} +// 根据项目ID获取招商团队信息 +export function getMerchantTeamByProjectId(projectId) { + return request({ + url: `/bizTeam/project/${projectId}`, + method: 'get' + }) +} + +export function addMerchantTeam(data) { + return request({ + url: '/bizTeam', + method: 'post', + data + }) +} + +export function updateMerchantTeam(data) { + return request({ + url: '/bizTeam', + method: 'put', + data + }) +} + +export function deleteMerchantTeam(id, userId) { + return request({ + url: `/bizTeam/${id}`, + method: 'delete', + params: { userId } + }) +} + +export function checkTeamName(params) { + return request({ + url: '/bizTeam/checkName', + method: 'get', + params + }) +} + +export function getProjectsList() { + return request({ + url: '/bizTeam/projects', + method: 'get' + }) +} + +// 招商人员相关API +export function getMerchantPersonnelList(data) { + return request({ + url: '/bizPersonnel/queryAllPersonnel', + method: 'post', + data + }) +} + +export function getPersonnelByTeamId(teamId) { + return request({ + url: `/business/personnel/team/${teamId}`, + method: 'get' + }) +} + +export function getPersonnelDetail(id) { + return request({ + url: `/business/personnel/${id}`, + method: 'get' + }) +} + +export function addMerchantPersonnel(data) { + return request({ + url: '/bizPersonnel', + method: 'post', + data + }) +} + +export function batchAddMerchantPersonnel(data) { + return request({ + url: '/bizPersonnel/batch', + method: 'post', + data + }) +} + +export function removeMerchantPersonnel(id, userId) { + return request({ + url: `/bizPersonnel/${id}`, + method: 'delete', + params: { userId } + }) +} + +export function checkMemberExists(params) { + return request({ + url: '/bizPersonnel/checkMember', + method: 'get', + params + }) +} + +// 成员管理相关API +export function getDepartmentTree() { + return request({ + url: '/business/member/dept/tree', + method: 'get' + }) +} + +export function getDepartmentMemberTree() { + return request({ + url: '/business/member/tree', + method: 'get' + }) +} + +export function getManagerList() { + return request({ + url: '/business/member/managers', + method: 'get' + }) +} + +export function getMemberList(params) { + return request({ + url: '/business/member/list', + method: 'get', + params + }) +} + +export function getMembersByDeptId(deptId) { + return request({ + url: `/business/member/dept/${deptId}`, + method: 'get' + }) +} + +export function getMemberDetail(memberId) { + return request({ + url: `/business/member/${memberId}`, + method: 'get' + }) +} + +// 获取项目列表 +export function getProjectList() { + return request({ + url: '/project/list', + method: 'get' + }) +} + +// 获取线索数量 +export function getClueCount(personnelId) { + return request({ + url: `/merchant/clue/count/${personnelId}`, + method: 'get' + }) +} + +// 获取意向客户数量 +export function getIntentCustomerCount(personnelId) { + return request({ + url: `/merchant/intent-customer/count/${personnelId}`, + method: 'get' + }) +} + +// 获取合同数量 +export function getContractCount(personnelId) { + return request({ + url: `/merchant/contract/count/${personnelId}`, + method: 'get' + }) +} + +// 标签分组相关API +export function getTagGroupList(params) { + return request({ + url: '/business/tag-group/list', + method: 'get', + params + }) +} + +export function getAllTagGroups() { + return request({ + url: '/business/tag-group/all', + method: 'get' + }) +} + +export function getTagGroupDetail(id) { + return request({ + url: `/business/tag-group/${id}`, + method: 'get' + }) +} + +export function addTagGroup(data) { + return request({ + url: '/business/tag-group', + method: 'post', + data + }) +} + +export function updateTagGroup(data) { + return request({ + url: '/business/tag-group', + method: 'put', + data + }) +} + +export function deleteTagGroup(id) { + return request({ + url: `/business/tag-group/${id}`, + method: 'delete' + }) +} + +export function checkTagGroupName(params) { + return request({ + url: '/business/tag-group/check-name', + method: 'get', + params + }) +} + +// 标签相关API +export function getTagList(params) { + return request({ + url: '/business/tag/list', + method: 'get', + params + }) +} + +export function getTagListByGroupId(groupId) { + return request({ + url: `/business/tag/group/${groupId}`, + method: 'get' + }) +} + +export function getTagDetail(id) { + return request({ + url: `/business/tag/${id}`, + method: 'get' + }) +} + +export function addTag(data) { + return request({ + url: '/business/tag', + method: 'post', + data + }) +} + +export function updateTag(data) { + return request({ + url: '/business/tag', + method: 'put', + data + }) +} + +export function deleteTag(id) { + return request({ + url: `/business/tag/${id}`, + method: 'delete' + }) +} + +export function checkTagName(params) { + return request({ + url: '/business/tag/check-name', + method: 'get', + params + }) +} + +// 线索状态API +export function getLeadStatusList() { + return request({ + url: '/bizLead/status/list', + method: 'get' + }) +} + +export function getLeadStatusDetail(id) { + return request({ + url: `/bizLead/status/${id}`, + method: 'get' + }) +} + +export function addLeadStatus(data) { + return request({ + url: '/bizLead/status', + method: 'post', + data + }) +} + +export function updateLeadStatus(data) { + return request({ + url: '/bizLead/status', + method: 'put', + data + }) +} + +export function deleteLeadStatus(id, userId) { + return request({ + url: `/bizLead/status/${id}`, + method: 'delete', + params: { userId } + }) +} + +export function checkLeadStatusName(statusName) { + return request({ + url: '/bizLead/status/checkName', + method: 'get', + params: { statusName } + }) +} + +// 线索管理API +export function getLeadList(params) { + return request({ + url: '/bizLead/list', + method: 'get', + params + }) +} + +export function getMyLeadList(params) { + return request({ + url: '/bizLead/myLeads', + method: 'get', + params + }) +} + +export function getAllLeadList(params) { + return request({ + url: '/bizLead/allLeads', + method: 'get', + params + }) +} + +export function getPublicLeadList(params) { + return request({ + url: '/bizLead/publicLeads', + method: 'get', + params + }) +} + +export function getLeadDetail(id) { + return request({ + url: `/bizLead/${id}`, + method: 'get' + }) +} + +export function addLead(data) { + return request({ + url: '/bizLead', + method: 'post', + data + }) +} + +export function updateLead(data) { + return request({ + url: '/bizLead', + method: 'put', + data + }) +} + +export function changeLeadStatus(id, statusId, userId) { + return request({ + url: `/bizLead/${id}/status`, + method: 'put', + params: { statusId, userId } + }) +} + +export function changeLeadPersonnel(id, personnelId, userId) { + return request({ + url: `/bizLead/${id}/personnel`, + method: 'put', + params: { personnelId, userId } + }) +} + +export function checkLeadPhone(phone) { + return request({ + url: '/bizLead/checkPhone', + method: 'get', + params: { phone } + }) +} + +export function convertLeadToIntention(id, userId) { + return request({ + url: `/bizLead/${id}/convert`, + method: 'post', + params: { userId } + }) +} + +export function deleteLead(id, userId) { + return request({ + url: `/bizLead/${id}`, + method: 'delete', + params: { userId } + }) +} + +export function getLeadFollowHistory(leadId) { + return request({ + url: `/bizLead/${leadId}/followHistory`, + method: 'get' + }) +} + +// 意向客户相关API +export function getCustomerDetail(id) { + return request({ + url: `/bizCustomer/${id}`, + method: 'get' + }) +} + +export function createCustomer(data) { + return request({ + url: '/bizCustomer', + method: 'post', + data + }) +} + +export function updateCustomer(data) { + return request({ + url: '/bizCustomer', + method: 'put', + data + }) +} + +export function deleteCustomer(id) { + return request({ + url: `/bizCustomer/${id}`, + method: 'delete' + }) +} + +export function changeCustomerPersonnel(id, personnelId) { + return request({ + url: `/bizCustomer/personnel/${id}/${personnelId}`, + method: 'put' + }) +} + +export function changeCustomerStatus(id, statusId) { + return request({ + url: `/bizCustomer/status/${id}/${statusId}`, + method: 'put' + }) +} + +export function checkCustomerPhone(params) { + return request({ + url: '/bizCustomer/checkPhone', + method: 'get', + params + }) +} + +export function getMyCustomerList(data) { + return request({ + url: '/bizCustomer/myCustomer', + method: 'post', + data + }) +} + +export function getAllCustomerList(data) { + return request({ + url: '/bizCustomer/allCustomer', + method: 'post', + data + }) +} + +export function getPublicCustomerList(data) { + return request({ + url: '/bizCustomer/publicCustomer', + method: 'post', + data + }) +} + +export function followCustomer(data) { + return request({ + url: '/bizCustomer/follow', + method: 'post', + data + }) +} + +export function getCustomerFollowHistory(customerId) { + return request({ + url: `/bizCustomer/followHistory/${customerId}`, + method: 'get' + }) +} + +export function assignCustomer(id, params) { + return request({ + url: `/bizCustomer/${id}/assign`, + method: 'post', + params + }) +} + +export function returnCustomerToPublic(id, userId) { + return request({ + url: `/bizCustomer/returnToPublic/${id}`, + method: 'post', + params: { userId } + }) +} + +export function getCustomerTagGroups() { + return request({ + url: '/bizCustomer/tags/groups', + method: 'get' + }) +} + +export function saveCustomerTags(data) { + return request({ + url: '/bizCustomer/tags', + method: 'post', + data + }) +} + +// 获取客户状态列表 +export function getCustomerStatusList() { + return request({ + url: '/bizCustomer/status/list', + method: 'get' + }) +} diff --git a/pc/src/api/project.js b/pc/src/api/project.js new file mode 100644 index 0000000..5878920 --- /dev/null +++ b/pc/src/api/project.js @@ -0,0 +1,70 @@ +import request from '@/utils/request' + +// 获取项目列表 +export function getProjectList(query) { + return request({ + url: '/room/project/list', + method: 'get', + params: query + }) +} + +// 获取项目详情 +export function getProjectDetail(id) { + return request({ + url: `/room/project/${id}`, + method: 'get' + }) +} + +// 新增项目 +export function addProject(data) { + return request({ + url: '/room/project/add', + method: 'post', + data: data + }) +} + +// 修改项目 +export function updateProject(id, data) { + const updateData = { ...data, id } + return request({ + url: '/room/project/edit', + method: 'post', + data: updateData + }) +} + +// 删除项目 +export function deleteProject(id) { + return request({ + url: `/room/project/remove/${id}`, + method: 'post' + }) +} + +// 获取项目统计数据 +export function getProjectStatistics(id) { + return request({ + url: `/room/project/${id}/statistics`, + method: 'get' + }) +} + +// 获取所有项目统计数据(整体概况) +export function getAllProjectStatistics() { + return request({ + url: '/room/project/statistics', + method: 'get' + }) +} + +// 获取标签列表 +export function getTagByType(data) { + return request({ + url: '/admin/tag/getTagsByType', + method: 'post', + data: data + }) +} \ No newline at end of file diff --git a/pc/src/api/resource.js b/pc/src/api/resource.js new file mode 100644 index 0000000..12fb916 --- /dev/null +++ b/pc/src/api/resource.js @@ -0,0 +1,54 @@ +import request from '@/utils/request' + +/** + * 上传附件 + * @param {File} file 文件对象 + * @returns {Promise} 返回包含fileId和fileName的Promise + */ +export function uploadAttachment(file) { + const formData = new FormData() + formData.append('file', file) + return request({ + url: '/resource/attachment/uploadAttachment', + method: 'post', + data: formData, + headers: { + 'Content-Type': 'multipart/form-data' + } + }) +} + +/** + * 下载附件 + * @param {string} fileId 文件ID + * @returns {Promise} 返回文件流的Promise + */ +export function downloadAttachment(fileId) { + return request({ + url: `/resource/attachment/downloadAttachment?fileId=${fileId}`, + method: 'get', + responseType: 'blob' + }) +} + +/** + * 批量删除附件 + * @param {Array} fileIds 文件ID数组 + * @returns {Promise} 返回操作结果的Promise + */ +export function batchDeleteAttachment(fileIds) { + return request({ + url: '/resource/attachment/batchDeleteAttachment', + method: 'post', + data: fileIds + }) +} + +/** + * 删除单个附件 + * @param {string} fileId 文件ID + * @returns {Promise} 返回操作结果的Promise + */ +export function deleteAttachment(fileId) { + return batchDeleteAttachment([fileId]) +} \ No newline at end of file diff --git a/pc/src/api/room.js b/pc/src/api/room.js new file mode 100644 index 0000000..79b20b2 --- /dev/null +++ b/pc/src/api/room.js @@ -0,0 +1,199 @@ +import request from '@/utils/request' + +// 查询房源列表 +export function listRoom(query) { + return request({ + url: '/room/list', + method: 'get', + params: query + }) +} + +// 查询房源详细信息 +export function getRoom(id) { + return request({ + url: '/room/' + id, + method: 'get' + }) +} + +// 新增房源 +export function addRoom(data) { + return request({ + url: '/room/add', + method: 'post', + data: data + }) +} + +// 修改房源 +export function updateRoom(data) { + return request({ + url: '/room/edit', + method: 'post', + data: data + }) +} + +// 删除房源 +export function delRoom(id) { + return request({ + url: '/room/remove/' + id, + method: 'post' + }) +} + +// 批量删除房源 +export function delRoomBatch(ids) { + return request({ + url: '/room/batch/remove/' + ids, + method: 'post' + }) +} + +// 导出房源 +export function exportRoom(query) { + return request({ + url: '/room/template/export/batch', + method: 'post', + data: query, + responseType: 'blob' + }) +} + +// 下载导入模板 +export function downloadTemplate() { + return request({ + url: '/room/template/download', + method: 'get', + responseType: 'blob' + }) +} + +// 导入房源数据 +export function importRoom(file) { + const formData = new FormData() + formData.append('file', file) + return request({ + url: '/room/import', + method: 'post', + data: formData, + headers: { + 'Content-Type': 'multipart/form-data' + } + }) +} + +// 查询房源标签列表 +export function listRoomTags() { + return request({ + url: '/room/tags', + method: 'get' + }) +} + +// 获取项目列表 +export function listProjects() { + return request({ + url: '/project/list', + method: 'get' + }) +} + +// 获取楼宇列表 +export function listBuildings(projectId) { + return request({ + url: '/building/list', + method: 'get', + params: { projectId } + }) +} + +// 获取楼层列表 +export function listFloors(buildingId) { + return request({ + url: '/building/floors', + method: 'get', + params: { buildingId } + }) +} + +// 远程调用 - 获取业户列表 +export function listOwners(query) { + return request({ + url: '/customer/owners', + method: 'get', + params: query + }) +} + +// 远程调用 - 检查房源合同状态 +export function checkRoomContractStatus(roomId) { + return request({ + url: '/contract/check/room/' + roomId, + method: 'get' + }) +} + +// 修改房源租赁状态 +export function updateRoomLeaseStatus(id, status) { + return request({ + url: '/room/lease-status', + method: 'post', + data: { id, status } + }) +} + +// 检查房号是否存在 +export function checkRoomNumberExists(params) { + return request({ + url: '/room/check-number', + method: 'get', + params: params + }) +} + +// 获取房源图片列表 +export function listRoomImages(params) { + return request({ + url: '/room/images', + method: 'get', + params: params + }) +} + +// 上传房源图片 +export function uploadRoomImage(roomId, imageType, file, sortOrder) { + const formData = new FormData() + formData.append('roomId', roomId) + formData.append('imageType', imageType) + formData.append('file', file) + if (sortOrder !== undefined) { + formData.append('sortOrder', sortOrder) + } + return request({ + url: '/room/upload', + method: 'post', + data: formData, + headers: { + 'Content-Type': 'multipart/form-data' + } + }) +} + +// 删除房源图片 +export function deleteRoomImage(id) { + return request({ + url: '/room/image/' + id, + method: 'post' + }) +} + +// 批量删除房源图片 +export function batchDeleteRoomImages(ids) { + return request({ + url: '/room/images/batch', + method: 'post', + data: { ids } + }) +} \ No newline at end of file diff --git a/pc/src/assets/images/code.png b/pc/src/assets/images/code.png new file mode 100644 index 0000000..67f1ea1 Binary files /dev/null and b/pc/src/assets/images/code.png differ diff --git a/pc/src/assets/images/qrcode.svg b/pc/src/assets/images/qrcode.svg new file mode 100644 index 0000000..9a30208 --- /dev/null +++ b/pc/src/assets/images/qrcode.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pc/src/assets/images/tag_01.png b/pc/src/assets/images/tag_01.png new file mode 100644 index 0000000..feeeb61 Binary files /dev/null and b/pc/src/assets/images/tag_01.png differ diff --git a/pc/src/assets/images/tag_02.png b/pc/src/assets/images/tag_02.png new file mode 100644 index 0000000..01b6dff Binary files /dev/null and b/pc/src/assets/images/tag_02.png differ diff --git a/pc/src/assets/images/tag_03.png b/pc/src/assets/images/tag_03.png new file mode 100644 index 0000000..53c3ccf Binary files /dev/null and b/pc/src/assets/images/tag_03.png differ diff --git a/pc/src/assets/images/tag_04.png b/pc/src/assets/images/tag_04.png new file mode 100644 index 0000000..2d275c2 Binary files /dev/null and b/pc/src/assets/images/tag_04.png differ diff --git a/pc/src/assets/styles/index.scss b/pc/src/assets/styles/index.scss new file mode 100644 index 0000000..2856549 --- /dev/null +++ b/pc/src/assets/styles/index.scss @@ -0,0 +1,24 @@ +html, body { + margin: 0; + padding: 0; + height: 100%; + font-family: Avenir, Helvetica, Arial, sans-serif; +} + +* { + box-sizing: border-box; +} + +.el-container { + height: 100%; +} + +.el-header { + padding: 0; + height: 60px; +} + +.el-main { + background-color: #f0f2f5; + padding: 20px; +} \ No newline at end of file diff --git a/pc/src/components/MemberSelector/index.vue b/pc/src/components/MemberSelector/index.vue new file mode 100644 index 0000000..b3cdfbf --- /dev/null +++ b/pc/src/components/MemberSelector/index.vue @@ -0,0 +1,655 @@ + + + + + \ No newline at end of file diff --git a/pc/src/components/RegionSelector.vue b/pc/src/components/RegionSelector.vue new file mode 100644 index 0000000..2713270 --- /dev/null +++ b/pc/src/components/RegionSelector.vue @@ -0,0 +1,136 @@ + + + + + \ No newline at end of file diff --git a/pc/src/layout/index.vue b/pc/src/layout/index.vue new file mode 100644 index 0000000..18de30d --- /dev/null +++ b/pc/src/layout/index.vue @@ -0,0 +1,112 @@ + + + + + \ No newline at end of file diff --git a/pc/src/main.js b/pc/src/main.js new file mode 100644 index 0000000..58a436d --- /dev/null +++ b/pc/src/main.js @@ -0,0 +1,50 @@ +import Vue from 'vue' +import App from './App.vue' +import router from './router' +import store from './store' +import ElementUI from 'element-ui' +import 'element-ui/lib/theme-chalk/index.css' +import './assets/styles/index.scss' + +Vue.use(ElementUI) +Vue.config.productionTip = false + +// 添加下载方法 +Vue.prototype.download = function(res, fileName) { + // 检查响应类型 + if (res.type && (res.type === 'application/vnd.ms-excel' || + res.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || + res.type.includes('excel') || + res.type === 'application/octet-stream')) { + // 如果已经是Blob类型且是Excel类型,直接使用 + const blob = res + const link = document.createElement('a') + link.href = URL.createObjectURL(blob) + link.download = fileName + link.click() + URL.revokeObjectURL(link.href) + } else { + // 如果不是Blob类型或无法确定类型,根据文件扩展名处理 + let blob + if (fileName.endsWith('.xlsx') || fileName.endsWith('.xls')) { + // Excel文件需要使用二进制格式 + blob = new Blob([res], { + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + }) + } else { + // 其他类型使用默认处理 + blob = new Blob([res]) + } + const link = document.createElement('a') + link.href = URL.createObjectURL(blob) + link.download = fileName + link.click() + URL.revokeObjectURL(link.href) + } +} + +new Vue({ + router, + store, + render: h => h(App) +}).$mount('#app') \ No newline at end of file diff --git a/pc/src/router/index.js b/pc/src/router/index.js new file mode 100644 index 0000000..58d4b6c --- /dev/null +++ b/pc/src/router/index.js @@ -0,0 +1,75 @@ +import Vue from 'vue' +import VueRouter from 'vue-router' +import Layout from '@/layout/index' +import systemRoutes from './modules/system' +import projectRoutes from './modules/project' +import financeRoutes from './modules/finance' +import merchantRoutes from './modules/merchant' + +Vue.use(VueRouter) + +const routes = [ + { + path: '/', + component: () => import('@/layout/index'), + redirect: '/home', + hidden: true + }, + { + path: '/home', + component: () => import('@/layout/index'), + children: [ + { + path: '', + name: 'Home', + component: () => import('../views/Home.vue'), + meta: { title: '首页', icon: 'el-icon-s-home' } + } + ], + meta: { title: '首页', icon: 'el-icon-s-home' } + }, + systemRoutes, + projectRoutes, + financeRoutes, + merchantRoutes, + { + path: '/asset', + component: Layout, + name: 'Asset', + meta: { title: '资产管理', icon: 'el-icon-s-management' }, + children: [ + { + path: 'location', + component: () => import('@/views/asset/location/index'), + name: 'AssetLocation', + meta: { title: '资产位置设置', icon: 'el-icon-location' } + }, + { + path: 'classification', + component: () => import('@/views/asset/classification/index'), + name: 'AssetClassification', + meta: { title: '资产分类设置', icon: 'el-icon-folder' } + }, + { + path: 'inventory', + component: () => import('@/views/asset/inventory/index'), + name: 'AssetInventory', + meta: { title: '资产清单管理', icon: 'el-icon-files' } + }, + { + path: 'labelPage', + component: () => import('@/views/asset/labelPage/index'), + name: 'AssetLabel', + meta: { title: '资产标签设置', icon: 'el-icon-printer' } + } + ] + } +] + +const router = new VueRouter({ + mode: 'history', + base: process.env.BASE_URL, + routes +}) + +export default router \ No newline at end of file diff --git a/pc/src/router/modules/finance.js b/pc/src/router/modules/finance.js new file mode 100644 index 0000000..fc11235 --- /dev/null +++ b/pc/src/router/modules/finance.js @@ -0,0 +1,54 @@ +import Layout from '@/layout/index' + +export default { + path: '/finance', + component: Layout, + name: 'Finance', + meta: { title: '业务财务', icon: 'el-icon-money' }, + redirect: '/finance/feeType', + children: [ + { + path: 'feeType', + component: () => import('@/views/finance/feeType/index.vue'), + name: 'FeeType', + meta: { title: '费用类型', icon: 'el-icon-tickets' } + }, + { + path: 'receiptSetting', + component: () => import('@/views/finance/receiptSetting/index.vue'), + name: 'ReceiptSetting', + meta: { title: '收据设置', icon: 'el-icon-document' } + }, + { + path: 'chargeStandard', + component: () => import('@/views/finance/chargeStandard/index.vue'), + name: 'ChargeStandard', + meta: { title: '收费标准', icon: 'el-icon-price-tag' } + }, + { + path: 'billList', + component: () => import('@/views/finance/billList/index.vue'), + name: 'BillList', + meta: { title: '所有账单', icon: 'el-icon-notebook-2' } + }, + { + path: 'transaction', + component: () => import('@/views/finance/transaction/index.vue'), + name: 'Transaction', + meta: { title: '收支流水', icon: 'el-icon-money' } + }, + { + path: 'receiptRecord', + component: () => import('@/views/finance/receiptRecord/index.vue'), + name: 'ReceiptRecord', + meta: { title: '收据记录', icon: 'el-icon-document-copy' } + }, + { + path: 'receipt/issue/:billId', + component: () => import('@/views/finance/receipt/issue.vue'), + name: 'IssueReceipt', + meta: { title: '开具收据', activeMenu: '/finance/billList' }, + hidden: true + } + ] +} \ No newline at end of file diff --git a/pc/src/router/modules/merchant.js b/pc/src/router/modules/merchant.js new file mode 100644 index 0000000..c049cae --- /dev/null +++ b/pc/src/router/modules/merchant.js @@ -0,0 +1,33 @@ +export default { + path: '/merchant', + component: () => import('@/layout/index'), + redirect: '/merchant/merchant-personnel', + name: 'Merchant', + meta: { title: '招商管理', icon: 'el-icon-user-solid' }, + children: [ + { + path: 'merchant-personnel', + component: () => import('@/views/merchant/merchant-personnel/index.vue'), + name: 'MerchantPersonnel', + meta: { title: '招商人员', icon: 'el-icon-user' } + }, + { + path: 'tag-management', + component: () => import('@/views/merchant/tag-management/index.vue'), + name: 'TagManagement', + meta: { title: '标签管理', icon: 'el-icon-collection-tag' } + }, + { + path: 'clue-management', + component: () => import('@/views/merchant/clue-management/index.vue'), + name: 'ClueManagement', + meta: { title: '线索管理', icon: 'el-icon-chat-line-square' } + }, + { + path: 'intent-customer', + component: () => import('@/views/merchant/intent-customer/index.vue'), + name: 'IntentCustomer', + meta: { title: '意向客户', icon: 'el-icon-s-custom' } + } + ] +} \ No newline at end of file diff --git a/pc/src/router/modules/project.js b/pc/src/router/modules/project.js new file mode 100644 index 0000000..ef3de56 --- /dev/null +++ b/pc/src/router/modules/project.js @@ -0,0 +1,27 @@ +export default { + path: '/project', + component: () => import('@/layout/index'), + redirect: '/project/list', + name: 'Project', + meta: { title: '项目管理', icon: 'el-icon-office-building' }, + children: [ + { + path: 'list', + name: 'ProjectList', + component: () => import('@/views/project/index'), + meta: { title: '项目列表' } + }, + { + path: 'building', + name: 'BuildingList', + component: () => import('@/views/project/building/index'), + meta: { title: '楼宇列表' } + }, + { + path: 'room', + name: 'RoomList', + component: () => import('@/views/project/room/index'), + meta: { title: '房源列表' } + } + ] +} \ No newline at end of file diff --git a/pc/src/router/modules/system.js b/pc/src/router/modules/system.js new file mode 100644 index 0000000..d610e93 --- /dev/null +++ b/pc/src/router/modules/system.js @@ -0,0 +1,15 @@ +export default { + path: '/system', + component: () => import('@/layout/index'), + redirect: '/system/department-member', + name: 'System', + meta: { title: '系统管理', icon: 'el-icon-s-tools' }, + children: [ + { + path: 'department-member', + component: () => import('@/views/system/department-member/index'), + name: 'DepartmentMember', + meta: { title: '部门成员管理', icon: 'el-icon-office-building' } + } + ] +} \ No newline at end of file diff --git a/pc/src/store/index.js b/pc/src/store/index.js new file mode 100644 index 0000000..3a7f2d7 --- /dev/null +++ b/pc/src/store/index.js @@ -0,0 +1,15 @@ +import Vue from 'vue' +import Vuex from 'vuex' + +Vue.use(Vuex) + +export default new Vuex.Store({ + state: { + }, + mutations: { + }, + actions: { + }, + modules: { + } +}) \ No newline at end of file diff --git a/pc/src/utils/auth.js b/pc/src/utils/auth.js new file mode 100644 index 0000000..92f056a --- /dev/null +++ b/pc/src/utils/auth.js @@ -0,0 +1,56 @@ +/** + * 用户鉴权相关工具方法 + */ + +/** + * 获取当前登录用户ID + * @returns {string} 用户ID + */ +export function getUserId() { + // 从本地存储中获取用户信息 + const userInfo = localStorage.getItem('userInfo') + if (userInfo) { + try { + const user = JSON.parse(userInfo) + return user.id || user.userId || '' + } catch (e) { + console.error('解析用户信息失败', e) + return '' + } + } + return '' +} + +/** + * 获取用户信息 + * @returns {Object} 用户信息对象 + */ +export function getUserInfo() { + const userInfo = localStorage.getItem('userInfo') + if (userInfo) { + try { + return JSON.parse(userInfo) + } catch (e) { + console.error('解析用户信息失败', e) + return {} + } + } + return {} +} + +/** + * 保存用户信息到本地存储 + * @param {Object} userInfo 用户信息对象 + */ +export function setUserInfo(userInfo) { + if (userInfo) { + localStorage.setItem('userInfo', JSON.stringify(userInfo)) + } +} + +/** + * 清除用户信息 + */ +export function clearUserInfo() { + localStorage.removeItem('userInfo') +} \ No newline at end of file diff --git a/pc/src/utils/constants.js b/pc/src/utils/constants.js new file mode 100644 index 0000000..1a20e8c --- /dev/null +++ b/pc/src/utils/constants.js @@ -0,0 +1,5 @@ +// API响应状态码 +export const API_SUCCESS_CODE = '0000000000000000' + + +// 其他常量可以在此添加 diff --git a/pc/src/utils/request.js b/pc/src/utils/request.js new file mode 100644 index 0000000..1efad82 --- /dev/null +++ b/pc/src/utils/request.js @@ -0,0 +1,57 @@ +import axios from 'axios' +import { Message } from 'element-ui' +import { API_SUCCESS_CODE } from './constants' + +// 创建axios实例 +const service = axios.create({ + baseURL: '/', // 修改为相对路径,使用代理 + // baseURL: process.env.VUE_APP_BASE_API, // 使用环境变量中的接口地址 + + timeout: 10000 // 请求超时时间 +}) + +// 请求拦截器 +service.interceptors.request.use( + config => { + // 可以在这里添加请求头等信息 + return config + }, + error => { + console.log(error) + return Promise.reject(error) + } +) + +// 响应拦截器 +service.interceptors.response.use( + response => { + // 如果是blob类型(文件下载),直接返回blob数据 + if (response.config.responseType === 'blob') { + return response.data + } + + const res = response.data + // 如果返回的状态码不是成功码,则判断为错误 + if (res.code !== API_SUCCESS_CODE) { + Message({ + message: res.msg || res.message || '系统错误', + type: 'error', + duration: 5 * 1000 + }) + return Promise.reject(new Error(res.msg || res.message || '系统错误')) + } else { + return res + } + }, + error => { + console.log('err' + error) + Message({ + message: error.message, + type: 'error', + duration: 5 * 1000 + }) + return Promise.reject(error) + } +) + +export default service \ No newline at end of file diff --git a/pc/src/views/Home.vue b/pc/src/views/Home.vue new file mode 100644 index 0000000..d53bc9c --- /dev/null +++ b/pc/src/views/Home.vue @@ -0,0 +1,84 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/asset/classification/index.vue b/pc/src/views/asset/classification/index.vue new file mode 100644 index 0000000..aea1b3e --- /dev/null +++ b/pc/src/views/asset/classification/index.vue @@ -0,0 +1,772 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/asset/inventory/components/AssetDetail.vue b/pc/src/views/asset/inventory/components/AssetDetail.vue new file mode 100644 index 0000000..eaaa81a --- /dev/null +++ b/pc/src/views/asset/inventory/components/AssetDetail.vue @@ -0,0 +1,273 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/asset/inventory/components/AssetForm.vue b/pc/src/views/asset/inventory/components/AssetForm.vue new file mode 100644 index 0000000..88e0912 --- /dev/null +++ b/pc/src/views/asset/inventory/components/AssetForm.vue @@ -0,0 +1,593 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/asset/inventory/components/AssetLabelPrint.vue b/pc/src/views/asset/inventory/components/AssetLabelPrint.vue new file mode 100644 index 0000000..bf0c003 --- /dev/null +++ b/pc/src/views/asset/inventory/components/AssetLabelPrint.vue @@ -0,0 +1,528 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/asset/inventory/components/AssetLabelPrint.zip b/pc/src/views/asset/inventory/components/AssetLabelPrint.zip new file mode 100644 index 0000000..db49963 Binary files /dev/null and b/pc/src/views/asset/inventory/components/AssetLabelPrint.zip differ diff --git a/pc/src/views/asset/inventory/index.vue b/pc/src/views/asset/inventory/index.vue new file mode 100644 index 0000000..5f7795d --- /dev/null +++ b/pc/src/views/asset/inventory/index.vue @@ -0,0 +1,851 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/asset/labelPage/index.vue b/pc/src/views/asset/labelPage/index.vue new file mode 100644 index 0000000..0f63e8a --- /dev/null +++ b/pc/src/views/asset/labelPage/index.vue @@ -0,0 +1,623 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/asset/location/index.vue b/pc/src/views/asset/location/index.vue new file mode 100644 index 0000000..eb36953 --- /dev/null +++ b/pc/src/views/asset/location/index.vue @@ -0,0 +1,785 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/finance/billList/components/AddBill.vue b/pc/src/views/finance/billList/components/AddBill.vue new file mode 100644 index 0000000..6ed1402 --- /dev/null +++ b/pc/src/views/finance/billList/components/AddBill.vue @@ -0,0 +1,977 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/finance/billList/components/BillDetail.vue b/pc/src/views/finance/billList/components/BillDetail.vue new file mode 100644 index 0000000..12b06dc --- /dev/null +++ b/pc/src/views/finance/billList/components/BillDetail.vue @@ -0,0 +1,2720 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/finance/billList/index.vue b/pc/src/views/finance/billList/index.vue new file mode 100644 index 0000000..9750392 --- /dev/null +++ b/pc/src/views/finance/billList/index.vue @@ -0,0 +1,463 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/finance/chargeStandard/index.vue b/pc/src/views/finance/chargeStandard/index.vue new file mode 100644 index 0000000..f882082 --- /dev/null +++ b/pc/src/views/finance/chargeStandard/index.vue @@ -0,0 +1,2672 @@ + + + + + diff --git a/pc/src/views/finance/feeType/index.vue b/pc/src/views/finance/feeType/index.vue new file mode 100644 index 0000000..9ae0efd --- /dev/null +++ b/pc/src/views/finance/feeType/index.vue @@ -0,0 +1,655 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/finance/receipt/issue.vue b/pc/src/views/finance/receipt/issue.vue new file mode 100644 index 0000000..bdd972a --- /dev/null +++ b/pc/src/views/finance/receipt/issue.vue @@ -0,0 +1,563 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/finance/receiptRecord/components/ReceiptDetailDialog.vue b/pc/src/views/finance/receiptRecord/components/ReceiptDetailDialog.vue new file mode 100644 index 0000000..27c48d8 --- /dev/null +++ b/pc/src/views/finance/receiptRecord/components/ReceiptDetailDialog.vue @@ -0,0 +1,829 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/finance/receiptRecord/index.vue b/pc/src/views/finance/receiptRecord/index.vue new file mode 100644 index 0000000..8318aed --- /dev/null +++ b/pc/src/views/finance/receiptRecord/index.vue @@ -0,0 +1,234 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/finance/receiptSetting/PayeeInfo.vue b/pc/src/views/finance/receiptSetting/PayeeInfo.vue new file mode 100644 index 0000000..262cadc --- /dev/null +++ b/pc/src/views/finance/receiptSetting/PayeeInfo.vue @@ -0,0 +1,582 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/finance/receiptSetting/ReceiptTemplate.vue b/pc/src/views/finance/receiptSetting/ReceiptTemplate.vue new file mode 100644 index 0000000..00fd6e4 --- /dev/null +++ b/pc/src/views/finance/receiptSetting/ReceiptTemplate.vue @@ -0,0 +1,943 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/finance/receiptSetting/index.vue b/pc/src/views/finance/receiptSetting/index.vue new file mode 100644 index 0000000..a194589 --- /dev/null +++ b/pc/src/views/finance/receiptSetting/index.vue @@ -0,0 +1,474 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/finance/transaction/components/TransactionDetail.vue b/pc/src/views/finance/transaction/components/TransactionDetail.vue new file mode 100644 index 0000000..ac342a0 --- /dev/null +++ b/pc/src/views/finance/transaction/components/TransactionDetail.vue @@ -0,0 +1,520 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/finance/transaction/index.vue b/pc/src/views/finance/transaction/index.vue new file mode 100644 index 0000000..7b19f8a --- /dev/null +++ b/pc/src/views/finance/transaction/index.vue @@ -0,0 +1,352 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/merchant/clue-management/index.vue b/pc/src/views/merchant/clue-management/index.vue new file mode 100644 index 0000000..a0c836d --- /dev/null +++ b/pc/src/views/merchant/clue-management/index.vue @@ -0,0 +1,1759 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/merchant/intent-customer/index.vue b/pc/src/views/merchant/intent-customer/index.vue new file mode 100644 index 0000000..1a91a81 --- /dev/null +++ b/pc/src/views/merchant/intent-customer/index.vue @@ -0,0 +1,1678 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/merchant/merchant-personnel/index.vue b/pc/src/views/merchant/merchant-personnel/index.vue new file mode 100644 index 0000000..0dd6442 --- /dev/null +++ b/pc/src/views/merchant/merchant-personnel/index.vue @@ -0,0 +1,1456 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/merchant/tag-management/index.vue b/pc/src/views/merchant/tag-management/index.vue new file mode 100644 index 0000000..f190844 --- /dev/null +++ b/pc/src/views/merchant/tag-management/index.vue @@ -0,0 +1,776 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/project/building/index.vue b/pc/src/views/project/building/index.vue new file mode 100644 index 0000000..56cf8c6 --- /dev/null +++ b/pc/src/views/project/building/index.vue @@ -0,0 +1,2007 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/project/index.vue b/pc/src/views/project/index.vue new file mode 100644 index 0000000..408e560 --- /dev/null +++ b/pc/src/views/project/index.vue @@ -0,0 +1,594 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/project/room/components/DetailView.vue b/pc/src/views/project/room/components/DetailView.vue new file mode 100644 index 0000000..c294a46 --- /dev/null +++ b/pc/src/views/project/room/components/DetailView.vue @@ -0,0 +1,353 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/project/room/components/RoomForm.vue b/pc/src/views/project/room/components/RoomForm.vue new file mode 100644 index 0000000..ed2bc10 --- /dev/null +++ b/pc/src/views/project/room/components/RoomForm.vue @@ -0,0 +1,1052 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/project/room/index.vue b/pc/src/views/project/room/index.vue new file mode 100644 index 0000000..b551603 --- /dev/null +++ b/pc/src/views/project/room/index.vue @@ -0,0 +1,776 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/system/department-member/index.vue b/pc/src/views/system/department-member/index.vue new file mode 100644 index 0000000..9f843fb --- /dev/null +++ b/pc/src/views/system/department-member/index.vue @@ -0,0 +1,946 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/system/department/index.vue b/pc/src/views/system/department/index.vue new file mode 100644 index 0000000..c9d8699 --- /dev/null +++ b/pc/src/views/system/department/index.vue @@ -0,0 +1,203 @@ + + + + + \ No newline at end of file diff --git a/pc/src/views/system/index.vue b/pc/src/views/system/index.vue new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/pc/src/views/system/index.vue @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pc/src/views/system/member/index.vue b/pc/src/views/system/member/index.vue new file mode 100644 index 0000000..a9ded78 --- /dev/null +++ b/pc/src/views/system/member/index.vue @@ -0,0 +1,285 @@ + + + + + \ No newline at end of file diff --git a/pc/vue.config.js b/pc/vue.config.js new file mode 100644 index 0000000..63e0e94 --- /dev/null +++ b/pc/vue.config.js @@ -0,0 +1,24 @@ +module.exports = { + publicPath: '/', + outputDir: 'dist', + assetsDir: 'static', + productionSourceMap: false, + devServer: { + port: 8080, + open: true, + overlay: { + warnings: false, + errors: true + }, + proxy: { + '/': { + target: 'http://192.168.137.3:8080/api/api', + // target: 'http://192.168.137.45:8080', + changeOrigin: true, + pathRewrite: { + '^/api': '/api' + } + } + } + } +} \ No newline at end of file diff --git a/园区前端.zip b/园区前端.zip new file mode 100644 index 0000000..def265b Binary files /dev/null and b/园区前端.zip differ diff --git a/园区前端/h5.zip b/园区前端/h5.zip new file mode 100644 index 0000000..4707fef Binary files /dev/null and b/园区前端/h5.zip differ diff --git a/园区前端/pc.zip b/园区前端/pc.zip new file mode 100644 index 0000000..3e9b0d1 Binary files /dev/null and b/园区前端/pc.zip differ