liu
2026-09-22 64494aadbcbdbe5c55d7260078479acba1d0e929
江苏商贸职业学院:接入产教融合学生端(uni-app),替换原前端工程

- 移除原 RuoYi-Vue3 管理端前端全部源码(含 src/public/html/.env 等)
- 引入产教融合实践教学管理平台学生端 H5(uni-app:登录/注册/忘记密码/填报)

Co-Authored-By: Claude <noreply@anthropic.com>
已修改7个文件
已添加21个文件
已删除603个文件
109762 ■■■■■ 文件已修改
.env.development 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.production 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.staging 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.github/FUNDING.yml 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LICENSE 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
README.md 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
bin/build.bat 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
bin/package.bat 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
bin/run-web.bat 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
html/ie.html 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
index.html 238 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json 13421 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pnpm-lock.yaml 4316 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/DHDCico.ico 补丁 | 查看 | 原始文档 | blame | 历史
public/HYSNico.ico 补丁 | 查看 | 原始文档 | blame | 历史
public/JZYJico.ico 补丁 | 查看 | 原始文档 | blame | 历史
public/WDSYico.ico 补丁 | 查看 | 原始文档 | blame | 历史
public/ZQHXico.ico 补丁 | 查看 | 原始文档 | blame | 历史
public/favicon.ico 补丁 | 查看 | 原始文档 | blame | 历史
shims-uni.d.ts 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/App.vue 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/auth.js 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/basicData/customerFile.js 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/basicData/product.js 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/basicData/supplierManageFile.js 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/collaborativeApproval/approvalProcess.js 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/collaborativeApproval/attendanceManagement.js 136 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/collaborativeApproval/knowledgeBase.js 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/collaborativeApproval/noticeManagement.js 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/collaborativeApproval/notificationManagement.js 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/collaborativeApproval/officeSupplies.js 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/collaborativeApproval/planTemplate.js 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/collaborativeApproval/rpaManagement.js 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/collaborativeApproval/sealManagement.js 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/customerService/index.js 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/energyManagement/index.js 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/energyManagement/waterManagement.js 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/equipmentManagement/brand.js 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/equipmentManagement/calibration.js 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/equipmentManagement/deviceInfo.js 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/equipmentManagement/ledger.js 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/equipmentManagement/measurementEquipment.js 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/equipmentManagement/repair.js 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/equipmentManagement/upkeep.js 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/fileManagement/bookshelf.js 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/fileManagement/borrow.js 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/fileManagement/document.js 189 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/fileManagement/return.js 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/fileManagement/statistics.js 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/financialManagement/expenseManagement.js 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/financialManagement/financialStatements.js 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/financialManagement/revenueManagement.js 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/inventoryManagement/stockIn.js 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/inventoryManagement/stockManage.js 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/inventoryManagement/stockOut.js 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/inventoryManagement/stockWarning.js 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/lavorissce/ledger.js 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/login.js 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/menu.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/monitor/cache.js 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/monitor/job.js 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/monitor/jobLog.js 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/monitor/logininfor.js 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/monitor/online.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/monitor/operlog.js 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/monitor/server.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/personnelManagement/employeeRecord.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/personnelManagement/onboarding.js 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/personnelManagement/payrollManagement.js 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/personnelManagement/scheduling.js 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/personnelManagement/selfService.js 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/procurementManagement/invoiceEntry.js 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/procurementManagement/paymentEntry.js 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/procurementManagement/paymentLedger.js 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/procurementManagement/procurementInvoiceLedger.js 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/procurementManagement/procurementLedger.js 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/procurementManagement/projectProfit.js 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/procurementManagement/taxComparison.js 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/productionManagement/operationScheduling.js 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/productionManagement/productionCosting.js 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/productionManagement/productionOrder.js 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/productionManagement/productionReporting.js 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/qualityManagement/metricMaintenance.js 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/qualityManagement/nonconformingManagement.js 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/qualityManagement/qualityInspectFile.js 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/qualityManagement/qualityInspectParam.js 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/qualityManagement/rawMaterialInspection.js 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/salesManagement/invoiceLedger.js 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/salesManagement/invoiceRegistration.js 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/salesManagement/receiptPayment.js 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/salesManagement/salesLedger.js 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/config.js 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/dept.js 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/dict/data.js 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/dict/type.js 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/menu.js 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/notice.js 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/post.js 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/role.js 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/user.js 159 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/task.js 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/tool/gen.js 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/viewIndex.js 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/401_images/401.gif 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/404_images/404.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/404_images/404_cloud.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/fonts/DIN Alternate Bold.ttf 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/fonts/font.css 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/png/1.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/png/2.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/png/3.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/png/4.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/png/5.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/png/支出.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/png/支出金额.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/png/收入列帐.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/png/收入收款.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/png/收入金额.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/404.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/bug.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/build.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/button.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/cascader.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/chart.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/checkbox.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/clipboard.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/code.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/color.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/component.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/dashboard.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/date-range.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/date.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/dict.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/documentation.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/download.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/drag.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/druid.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/edit.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/education.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/email.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/example.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/excel.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/exit-fullscreen.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/eye-open.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/eye.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/form.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/fullscreen.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/github.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/guide.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/icon.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/input.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/international.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/job.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/language.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/link.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/list.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/lock.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/log.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/logininfor.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/message.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/money.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/monitor.svg 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/moon.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/nested.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/number.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/online.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/password.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/pdf.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/people.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/peoples.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/phone.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/post.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/qq.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/question.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/radio.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/rate.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/redis-list.svg 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/redis.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/row.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/search.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/select.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/server.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/shopping.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/size.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/skill.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/slider.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/star.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/sunny.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/swagger.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/switch.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/system.svg 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/tab.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/table.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/textarea.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/theme.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/time-range.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/time.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/tool.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/tree-table.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/tree.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/upload.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/user.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/validCode.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/wechat.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icons/svg/zip.svg 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/Rectangle 76@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/Rectangle 77@2x(1).png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/Rectangle 77@2x.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/caigou.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/chuchang.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/dark.svg 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/denglu.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/guocheng.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/icon 3.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/icon1.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/icon2.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/khtitle.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/kucun.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/light.svg 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/login-background.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/pay.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/profile.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/xioashoushuju.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/images/yuancailiao.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/clown-face.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/face-screaming-in-fear.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/face-vomiting.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/face-with-tongue.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/face-without-mouth.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/ghost.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/hibiscus.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/jack-o-lantern.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/lips.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/loudly-crying-face.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/money-bag.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/money-mouth-face.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/new-moon-face.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/ok-hand-yellow.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/pile-of-poo.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/pouting-face.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/rainbow.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/rocket.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/shamrock.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/shangchuan.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/slightly-smiling-face.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/smiling-face-with-heart-eyes.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/smiling-face-with-horns.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/smiling-face-with-sunglasses.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/smiling-face.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/sparkles.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/star.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/thinking-face.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/thought-balloon.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/thumbs-up-yellow.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/tired-face.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/two-hearts.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/victory-hand-yellow.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/emoji/取消.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/fileImg/excel.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/fileImg/pdf.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/fileImg/ppt.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/fileImg/txt.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/fileImg/unknowfile.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/fileImg/word.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/fileImg/zpi.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/head_portrait.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/head_portrait1.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/logo.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/indexViews/DHDCLogo.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/indexViews/DHDCView.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/indexViews/HYSNLogo.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/indexViews/HYSNView.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/indexViews/JZYJLogo.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/indexViews/JZYJView.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/indexViews/WDSYLogo.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/indexViews/WDSYView.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/indexViews/ZQHXLogo.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/indexViews/ZQHXView.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/logo/logo.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/logo/上海郢昱网络科技有限公司.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/logo/南通云从工业互联网有限公司.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/logo/敦煌鼎诚.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/logo/新缆(江苏)数字科技有限公司.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/logo/芯导软件(江苏)有限公司.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/btn.scss 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/element-ui.scss 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/index.scss 195 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/mixin.scss 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/ruoyi.scss 289 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/sidebar.scss 240 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/transition.scss 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/styles/variables.module.scss 221 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Breadcrumb/index.vue 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Crontab/day.vue 174 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Crontab/hour.vue 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Crontab/index.vue 309 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Crontab/min.vue 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Crontab/month.vue 141 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Crontab/result.vue 540 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Crontab/second.vue 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Crontab/week.vue 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Crontab/year.vue 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/DictTag/index.vue 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/DynamicTable/index.vue 402 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Echarts/echarts.vue 159 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Editor/index.vue 292 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/FileCard.vue 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/FileUpload/index.vue 259 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Hamburger/index.vue 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/HeaderSearch/index.vue 218 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/IconSelect/index.vue 111 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/IconSelect/requireIcons.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/ImagePreview/index.vue 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/ImageUpload/index.vue 256 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/PIMTable/PIMTable.vue 429 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/PIMTable/Pagination.vue 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Pagination/index.vue 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/ParentView/index.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/QRCodeGenerator/index.vue 541 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/RightToolbar/index.vue 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/RuoYi/Doc/index.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/RuoYi/Git/index.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Screenfull/index.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/SizeSelect/index.vue 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/SvgIcon/index.vue 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/SvgIcon/svgicon.js 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/TopNav/index.vue 217 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Upload/FileUpload.vue 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Upload/index.js 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/filePreview/index.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/iFrame/index.vue 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/config.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/directive/common/copyText.js 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/directive/index.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/directive/permission/hasPermi.js 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/directive/permission/hasRole.js 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/hooks/useFormData.js 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/hooks/useModal.js 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/hooks/usePaginationApi.jsx 145 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/AppMain.vue 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/IframeToggle/index.vue 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/InnerLink/index.vue 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Navbar.vue 269 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Settings/index.vue 259 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Sidebar/Link.vue 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Sidebar/Logo.vue 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Sidebar/SidebarItem.vue 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/Sidebar/index.vue 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/TagsView/ScrollPane.vue 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/TagsView/index.vue 355 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/components/index.js 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layout/index.vue 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.js 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/manifest.json 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages.json 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/forgot/forgot.vue 170 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/index/index.vue 259 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/login/login.vue 166 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/password/change.vue 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/plan/form.vue 597 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/register/register.vue 238 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/permission.js 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/auth.js 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/cache.js 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/download.js 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/index.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/modal.js 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/plugins/tab.js 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 201 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/settings.js 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/shime-uni.d.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/static/logo-emblem-white.png 补丁 | 查看 | 原始文档 | blame | 历史
src/static/logo-head-white.png 补丁 | 查看 | 原始文档 | blame | 历史
src/static/logo-navy.png 补丁 | 查看 | 原始文档 | blame | 历史
src/static/logo.png 补丁 | 查看 | 原始文档 | blame | 历史
src/store/index.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/app.js 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/dict.js 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/permission.js 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/settings.js 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/tagsView.js 182 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/modules/user.js 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/uni.scss 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/auth.js 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/dict.js 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/dynamicTitle.js 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/errorCode.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/generator/config.js 452 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/generator/css.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/generator/drawingDefalut.js 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/generator/html.js 359 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/generator/icon.json 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/generator/js.js 370 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/generator/render.js 156 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/index.js 398 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/jsencrypt.js 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/permission.js 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/region.js 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/request.js 266 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/ruoyi.js 228 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/scroll-to.js 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/site.js 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/summarizeTable.js 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/theme.js 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/util.js 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/validate.js 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/customerFile/index.vue 598 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/product/ImportExcel/index.vue 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/product/index.vue 500 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/supplierManage/index.vue 528 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/chatHome/chatHomeIndex/MobileChat.vue 461 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/chatHome/chatHomeIndex/ai-jz.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/chatHome/chatHomeIndex/ai-wd.js 393 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/chatHome/chatHomeIndex/home.vue 175 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue 371 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue 361 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/fileList.vue 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/index.vue 272 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/index1.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/index2.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/index3.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/approvalProcess/index4.vue 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/attendanceManagement/index.vue 923 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/knowledgeBase/index.vue 822 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/meetingBoard/index.vue 498 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/noticeManagement/index.vue 711 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/notificationManagement/index.vue 1202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/officeSupplies/index.vue 512 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/planTemplate/index.vue 867 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/rpaManagement/index.vue 359 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/sealManagement/index.vue 811 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/collaborativeApproval/warningSystem/index.vue 307 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/customerService/afterSalesHandling/components/formDia.vue 212 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/customerService/afterSalesHandling/index.vue 235 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/customerService/feedbackRegistration/components/formDia.vue 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/customerService/feedbackRegistration/index.vue 212 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/demo/fakePage/index.vue 248 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/dynamicEnergySaving/index.vue 659 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/energyArea/index.vue 511 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/energyCockpit/index.vue 1380 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/energyPeriodTime/index.vue 444 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/energyPower/components/formDia.vue 235 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/energyPower/index.vue 305 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/energyTrends/index.vue 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/gasManagement/index.vue 624 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/meterCollection/index.vue 556 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/waterManagement/components/formDia.vue 221 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/waterManagement/components/waterBillForm.vue 210 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/waterManagement/index.vue 312 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/waterManagement/waterBill.vue 181 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/energyManagement/waterManagement/waterTrends.vue 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/brand/index.vue 217 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/calibration/index.vue 218 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/deviceInfo/index.vue 190 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/gasTank/simple.vue 566 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/iotMonitor/index.vue 317 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/iotMonitor/indexWD.vue 317 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/ledger/Form.vue 227 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/ledger/Modal.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/ledger/index.vue 328 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/measurementEquipment/components/calibrationDia.vue 267 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/measurementEquipment/components/formDia.vue 253 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/measurementEquipment/filesDia.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/measurementEquipment/index.vue 276 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/Form/MaintainForm.vue 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/Form/RepairForm.vue 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/Modal/MaintainModal.vue 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/Modal/RepairModal.vue 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/index.vue 306 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Form/MaintenanceForm.vue 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Form/PlanForm.vue 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Modal/MaintenanceModal.vue 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Modal/PlanModal.vue 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/index.vue 293 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/error/401.vue 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/error/404.vue 227 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/example/DynamicTableExample.vue 354 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/example/SimpleExample.vue 135 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fileManagement/bookshelf/detail.vue 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fileManagement/bookshelf/index.vue 688 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fileManagement/borrow/index.vue 582 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fileManagement/document/attachmentManager.vue 426 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fileManagement/document/index.vue 1262 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fileManagement/return/index.vue 595 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fileManagement/statistics/index.vue 539 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/expenseManagement/Form.vue 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/expenseManagement/Modal.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/expenseManagement/index.vue 279 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/financialStatements/index.vue 513 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/revenueManagement/Form.vue 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/revenueManagement/Modal.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/revenueManagement/filesDia.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/financialManagement/revenueManagement/index.vue 279 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/index.vue 805 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/dispatchLog/index.vue 853 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/index.vue 309 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/issueManagement/index.vue 282 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/receiptManagement/index.vue 451 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockManagement/index.vue 382 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockWarning/index.vue 943 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/lavorissue/ledger/Form.vue 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/lavorissue/ledger/Modal.vue 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/lavorissue/ledger/filesDia.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/lavorissue/ledger/index.vue 300 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/lavorissue/statistics/index.vue 285 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login.vue 255 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/cache/index.vue 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/cache/list.vue 246 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/druid/index.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/job/index.vue 501 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/job/log.vue 283 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/logininfor/index.vue 233 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/online/index.vue 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/operlog/index.vue 313 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/monitor/server/index.vue 190 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/analytics/index.vue 698 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/contractManagement/components/formDia.vue 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/contractManagement/filesDia.vue 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/contractManagement/index.vue 329 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/dimission/components/formDia.vue 290 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/dimission/index.vue 284 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/employeeRecord/components/formDia.vue 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/employeeRecord/index.vue 249 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/onboarding/components/formDia.vue 259 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/onboarding/index.vue 284 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/payrollManagement/components/formDia.vue 315 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/payrollManagement/index.vue 291 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/scheduling/index.vue 601 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/personnelManagement/selfService/index.vue 805 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/arrivalManagement/index.vue 189 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/index.vue 378 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/components/ExpandTable.vue 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/components/Modal.vue 456 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/index.vue 294 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/invoiceEntry/indexOld.vue 727 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/paymentEntry/index.vue 580 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/paymentHistory/index.vue 173 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/paymentLedger/index.vue 315 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/priceManagement/index.vue 276 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementInvoiceLedger/Form/EditForm.vue 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementInvoiceLedger/Modal/EditModal.vue 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementInvoiceLedger/Modal/UploadModal.vue 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementInvoiceLedger/index.vue 362 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementInvoiceLedger/indexOld.vue 311 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/procurementLedger/index.vue 1577 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/purchaseOrder/index.vue 188 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/qualityInspection/index.vue 285 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/returnManagement/index.vue 234 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/procurementManagement/thePaymentLedger/index.vue 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productManagement/productIdentifier/index.vue 708 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/operationScheduling/components/formDia.vue 185 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/operationScheduling/index.vue 258 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionCosting/index.vue 186 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionDispatching/components/formDia.vue 169 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionDispatching/index.vue 204 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionOrder/index.vue 190 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionReporting/components/formDia.vue 155 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionReporting/index.vue 430 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/safetyMonitoring/index.vue 873 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/finalInspection/components/filesDia.vue 190 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/finalInspection/components/formDia.vue 278 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/finalInspection/components/inspectionFormDia.vue 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/finalInspection/index.vue 381 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/metricMaintenance/index.vue 415 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/nonconformingManagement/components/formDia.vue 249 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/nonconformingManagement/components/inspectionFormDia.vue 257 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/nonconformingManagement/index.vue 307 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/processInspection/components/filesDia.vue 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/processInspection/components/formDia.vue 285 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/processInspection/components/inspectionFormDia.vue 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/processInspection/index.vue 380 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/rawMaterialInspection/components/filesDia.vue 198 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/rawMaterialInspection/components/formDia.vue 302 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/rawMaterialInspection/components/inspectionFormDia.vue 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/rawMaterialInspection/index.vue 382 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/qualityManagement/visualization/qualityDashboard.vue 307 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/redirect/index.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/register.vue 220 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/projectProfit/index.vue 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/reportManagement.vue 733 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/reportManagement/index.vue 716 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/reportAnalysis/taxComparison/index.vue 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/customerManagement/index.vue 423 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/invoiceLedger/index.vue 448 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/invoiceRegistration/index.vue 668 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/orderManagement/index.vue 495 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/paymentShipping/index.vue 534 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/receiptPayment/index.vue 627 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/receiptPaymentHistory/index.vue 221 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/receiptPaymentLedger/index.vue 271 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/salesLedger/fileList.vue 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/salesLedger/index.vue 1004 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/salesManagement/salespersonManagement/index.vue 392 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/config/index.vue 316 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dept/index.vue 290 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dict/data.vue 362 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dict/index.vue 326 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/menu/index.vue 455 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/notice/index.vue 295 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/post/index.vue 290 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/role/authUser.vue 182 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/role/index.vue 587 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/role/selectUser.vue 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/authRole.vue 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/index.vue 902 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/profile/index.vue 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/profile/resetPwd.vue 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/profile/userAvatar.vue 168 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/user/profile/userInfo.vue 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tideLogin.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/build/CodeTypeDialog.vue 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/build/DraggableItem.vue 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/build/IconsDialog.vue 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/build/RightPanel.vue 906 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/build/TreeNodeDialog.vue 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/build/index.vue 653 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/gen/basicInfoForm.vue 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/gen/createTable.vue 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/gen/editTable.vue 200 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/gen/genInfoForm.vue 305 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/gen/importTable.vue 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/gen/index.vue 437 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tool/swagger/index.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite.config.js 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite/plugins/auto-import.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite/plugins/compression.js 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite/plugins/index.js 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite/plugins/setup-extend.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite/plugins/svg-icon.js 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.development
ÎļþÒÑɾ³ý
.env.production
ÎļþÒÑɾ³ý
.env.staging
ÎļþÒÑɾ³ý
.github/FUNDING.yml
ÎļþÒÑɾ³ý
.gitignore
@@ -1,23 +1,21 @@
.DS_Store
node_modules/
dist/
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
**/*.log
pnpm-debug.log*
lerna-debug.log*
tests/**/coverage/
tests/e2e/reports
selenium-debug.log
node_modules
.DS_Store
dist
*.local
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.local
package-lock.json
yarn.lock
*.sw?
LICENSE
ÎļþÒÑɾ³ý
README.md
ÎļþÒÑɾ³ý
bin/build.bat
ÎļþÒÑɾ³ý
bin/package.bat
ÎļþÒÑɾ³ý
bin/run-web.bat
ÎļþÒÑɾ³ý
html/ie.html
ÎļþÒÑɾ³ý
index.html
@@ -1,217 +1,21 @@
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="renderer" content="webkit" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
    />
    <link rel="icon" href="/DHDCico.ico" />
    <title>敦煌鼎诚管理信息系统</title>
    <!--[if lt IE 11
      ]><script>
        window.location.href = "/html/ie.html";
      </script><!
    [endif]-->
    <style>
      html,
      body,
      #app {
        height: 100%;
        margin: 0px;
        padding: 0px;
      }
      .chromeframe {
        margin: 0.2em 0;
        background: #ccc;
        color: #000;
        padding: 0.2em 0;
      }
      #loader-wrapper {
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        z-index: 999999;
      }
      #loader {
        display: block;
        position: relative;
        left: 50%;
        top: 50%;
        width: 150px;
        height: 150px;
        margin: -75px 0 0 -75px;
        border-radius: 50%;
        border: 3px solid transparent;
        border-top-color: #fff;
        -webkit-animation: spin 2s linear infinite;
        -ms-animation: spin 2s linear infinite;
        -moz-animation: spin 2s linear infinite;
        -o-animation: spin 2s linear infinite;
        animation: spin 2s linear infinite;
        z-index: 1001;
      }
      #loader:before {
        content: "";
        position: absolute;
        top: 5px;
        left: 5px;
        right: 5px;
        bottom: 5px;
        border-radius: 50%;
        border: 3px solid transparent;
        border-top-color: #fff;
        -webkit-animation: spin 3s linear infinite;
        -moz-animation: spin 3s linear infinite;
        -o-animation: spin 3s linear infinite;
        -ms-animation: spin 3s linear infinite;
        animation: spin 3s linear infinite;
      }
      #loader:after {
        content: "";
        position: absolute;
        top: 15px;
        left: 15px;
        right: 15px;
        bottom: 15px;
        border-radius: 50%;
        border: 3px solid transparent;
        border-top-color: #fff;
        -moz-animation: spin 1.5s linear infinite;
        -o-animation: spin 1.5s linear infinite;
        -ms-animation: spin 1.5s linear infinite;
        -webkit-animation: spin 1.5s linear infinite;
        animation: spin 1.5s linear infinite;
      }
      @-webkit-keyframes spin {
        0% {
          -webkit-transform: rotate(0deg);
          -ms-transform: rotate(0deg);
          transform: rotate(0deg);
        }
        100% {
          -webkit-transform: rotate(360deg);
          -ms-transform: rotate(360deg);
          transform: rotate(360deg);
        }
      }
      @keyframes spin {
        0% {
          -webkit-transform: rotate(0deg);
          -ms-transform: rotate(0deg);
          transform: rotate(0deg);
        }
        100% {
          -webkit-transform: rotate(360deg);
          -ms-transform: rotate(360deg);
          transform: rotate(360deg);
        }
      }
      #loader-wrapper .loader-section {
        position: fixed;
        top: 0;
        width: 51%;
        height: 100%;
        background: #7171c6;
        z-index: 1000;
        -webkit-transform: translateX(0);
        -ms-transform: translateX(0);
        transform: translateX(0);
      }
      #loader-wrapper .loader-section.section-left {
        left: 0;
      }
      #loader-wrapper .loader-section.section-right {
        right: 0;
      }
      .loaded #loader-wrapper .loader-section.section-left {
        -webkit-transform: translateX(-100%);
        -ms-transform: translateX(-100%);
        transform: translateX(-100%);
        -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
        transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
      }
      .loaded #loader-wrapper .loader-section.section-right {
        -webkit-transform: translateX(100%);
        -ms-transform: translateX(100%);
        transform: translateX(100%);
        -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
        transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
      }
      .loaded #loader {
        opacity: 0;
        -webkit-transition: all 0.3s ease-out;
        transition: all 0.3s ease-out;
      }
      .loaded #loader-wrapper {
        visibility: hidden;
        -webkit-transform: translateY(-100%);
        -ms-transform: translateY(-100%);
        transform: translateY(-100%);
        -webkit-transition: all 0.3s 1s ease-out;
        transition: all 0.3s 1s ease-out;
      }
      .no-js #loader-wrapper {
        display: none;
      }
      .no-js h1 {
        color: #222222;
      }
      #loader-wrapper .load_title {
        font-family: "Open Sans";
        color: #fff;
        font-size: 19px;
        width: 100%;
        text-align: center;
        z-index: 9999999999999;
        position: absolute;
        top: 60%;
        opacity: 1;
        line-height: 30px;
      }
      #loader-wrapper .load_title span {
        font-weight: normal;
        font-style: italic;
        font-size: 13px;
        color: #fff;
        opacity: 0.5;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <div id="loader-wrapper">
        <div id="loader"></div>
        <div class="loader-section section-left"></div>
        <div class="loader-section section-right"></div>
        <div class="load_title">正在加载系统资源,请耐心等待</div>
      </div>
    </div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/png" href="/static/logo.png" />
    <script>
      var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
        CSS.supports('top: constant(a)'))
      document.write(
        '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
        (coverSupport ? ', viewport-fit=cover' : '') + '" />')
    </script>
    <title>产教融合实践教学管理平台 Â· æ±Ÿè‹å•†è´¸èŒä¸šå­¦é™¢</title>
    <!--preload-links-->
    <!--app-context-->
  </head>
  <body>
    <div id="app"><!--app-html--></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>
package-lock.json
¶Ô±ÈÐÂÎļþ
ÎļþÌ«´ó
package.json
@@ -1,57 +1,68 @@
{
  "name": "ruoyi",
  "version": "3.8.9",
  "description": "敦煌鼎诚管理信息系统",
  "author": "若依",
  "license": "MIT",
  "type": "module",
  "name": "uni-preset-vue",
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build:prod": "vite build",
    "build:stage": "vite build --mode staging",
    "preview": "vite preview"
  },
  "repository": {
    "type": "git",
    "url": "https://gitee.com/y_project/RuoYi-Vue.git"
    "dev:custom": "uni -p",
    "dev:h5": "uni",
    "dev:h5:ssr": "uni --ssr",
    "dev:mp-alipay": "uni -p mp-alipay",
    "dev:mp-baidu": "uni -p mp-baidu",
    "dev:mp-jd": "uni -p mp-jd",
    "dev:mp-kuaishou": "uni -p mp-kuaishou",
    "dev:mp-lark": "uni -p mp-lark",
    "dev:mp-qq": "uni -p mp-qq",
    "dev:mp-toutiao": "uni -p mp-toutiao",
    "dev:mp-harmony": "uni -p mp-harmony",
    "dev:mp-weixin": "uni -p mp-weixin",
    "dev:mp-xhs": "uni -p mp-xhs",
    "dev:quickapp-webview": "uni -p quickapp-webview",
    "dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei",
    "dev:quickapp-webview-union": "uni -p quickapp-webview-union",
    "build:custom": "uni build -p",
    "build:h5": "uni build",
    "build:h5:ssr": "uni build --ssr",
    "build:mp-alipay": "uni build -p mp-alipay",
    "build:mp-baidu": "uni build -p mp-baidu",
    "build:mp-jd": "uni build -p mp-jd",
    "build:mp-kuaishou": "uni build -p mp-kuaishou",
    "build:mp-lark": "uni build -p mp-lark",
    "build:mp-qq": "uni build -p mp-qq",
    "build:mp-toutiao": "uni build -p mp-toutiao",
    "build:mp-harmony": "uni build -p mp-harmony",
    "build:mp-weixin": "uni build -p mp-weixin",
    "build:mp-xhs": "uni build -p mp-xhs",
    "build:quickapp-webview": "uni build -p quickapp-webview",
    "build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei",
    "build:quickapp-webview-union": "uni build -p quickapp-webview-union"
  },
  "dependencies": {
    "@element-plus/icons-vue": "2.3.1",
    "@vue-office/docx": "^1.6.3",
    "@vue-office/excel": "^1.7.14",
    "@vueup/vue-quill": "1.2.0",
    "@vueuse/core": "10.11.0",
    "axios": "0.28.1",
    "clipboard": "2.0.11",
    "dayjs": "^1.11.13",
    "echarts": "5.5.1",
    "element-plus": "2.7.7",
    "file-saver": "2.0.5",
    "fuse.js": "6.6.2",
    "js-beautify": "1.14.11",
    "js-cookie": "3.0.5",
    "jsencrypt": "3.3.2",
    "nprogress": "0.2.0",
    "pinia": "2.1.7",
    "qrcode": "^1.5.4",
    "sortablejs": "^1.15.6",
    "splitpanes": "3.1.5",
    "vue": "3.4.31",
    "vue-cropper": "1.1.1",
    "vue-esign": "^1.1.4",
    "vue-router": "4.4.0",
    "vuedraggable": "4.1.0"
    "@dcloudio/uni-app": "3.0.0-5020420260813003",
    "@dcloudio/uni-app-harmony": "3.0.0-5020420260813003",
    "@dcloudio/uni-app-plus": "3.0.0-5020420260813003",
    "@dcloudio/uni-components": "3.0.0-5020420260813003",
    "@dcloudio/uni-h5": "3.0.0-5020420260813003",
    "@dcloudio/uni-mp-alipay": "3.0.0-5020420260813003",
    "@dcloudio/uni-mp-baidu": "3.0.0-5020420260813003",
    "@dcloudio/uni-mp-harmony": "3.0.0-5020420260813003",
    "@dcloudio/uni-mp-jd": "3.0.0-5020420260813003",
    "@dcloudio/uni-mp-kuaishou": "3.0.0-5020420260813003",
    "@dcloudio/uni-mp-lark": "3.0.0-5020420260813003",
    "@dcloudio/uni-mp-qq": "3.0.0-5020420260813003",
    "@dcloudio/uni-mp-toutiao": "3.0.0-5020420260813003",
    "@dcloudio/uni-mp-weixin": "3.0.0-5020420260813003",
    "@dcloudio/uni-mp-xhs": "3.0.0-5020420260813003",
    "@dcloudio/uni-quickapp-webview": "3.0.0-5020420260813003",
    "vue": "^3.4.21",
    "vue-i18n": "^9.1.9"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "5.0.5",
    "sass": "1.77.5",
    "unplugin-auto-import": "0.17.6",
    "unplugin-vue-setup-extend-plus": "1.0.1",
    "vite": "5.3.2",
    "vite-plugin-compression": "0.5.1",
    "vite-plugin-svg-icons": "2.0.1"
  },
  "overrides": {
    "quill": "2.0.2"
    "@dcloudio/types": "^3.4.8",
    "@dcloudio/uni-automator": "3.0.0-5020420260813003",
    "@dcloudio/uni-cli-shared": "3.0.0-5020420260813003",
    "@dcloudio/uni-stacktracey": "3.0.0-5020420260813003",
    "@dcloudio/vite-plugin-uni": "3.0.0-5020420260813003",
    "@vue/runtime-core": "^3.4.21",
    "rollup": "4.14.3",
    "vite": "5.2.8"
  }
}
pnpm-lock.yaml
ÎļþÒÑɾ³ý
public/DHDCico.ico
Binary files differ
public/HYSNico.ico
Binary files differ
public/JZYJico.ico
Binary files differ
public/WDSYico.ico
Binary files differ
public/ZQHXico.ico
Binary files differ
public/favicon.ico
Binary files differ
shims-uni.d.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,10 @@
/// <reference types='@dcloudio/types' />
import 'vue'
declare module '@vue/runtime-core' {
  type Hooks = App.AppInstance & Page.PageInstance;
  interface ComponentCustomOptions extends Hooks {
  }
}
src/App.vue
@@ -1,15 +1,26 @@
<template>
  <router-view />
</template>
<script setup>
import useSettingsStore from '@/store/modules/settings'
import { handleThemeStyle } from '@/utils/theme'
onMounted(() => {
  nextTick(() => {
    // åˆå§‹åŒ–主题样式
    handleThemeStyle(useSettingsStore().theme)
  })
})
<script>
export default {
  onLaunch: function () {
    console.log('App Launch')
  },
  onShow: function () {
    console.log('App Show')
  },
  onHide: function () {
    console.log('App Hide')
  },
}
</script>
<style>
/*每个页面公共css */
/* é€‰æ‹©æ»šè½®/下拉弹层选项:长文本强制单行省略,防止换行撑乱滚轮行高。
   å¼¹å±‚挂在组件树外,必须用全局样式兜底(覆盖旧版式样与第三方样式注入场景)。 */
.uni-picker-container .uni-picker-item,
.uni-picker-container uni-picker-item {
  white-space: nowrap !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
}
</style>
src/api/auth.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,58 @@
/**
 * å­¦ç”Ÿç«¯ API:账号体系(班级码注册 / ç™»å½• / æ‰¾å›ž / æ”¹å¯†ï¼‰
 */
import r from '@/utils/request.js'
// èŽ·å–å½“å‰å­¦ç”Ÿä¿¡æ¯
export function getStudentInfo() {
  return r.get('/miniapp/my-info')
}
// ========== ç«™ç‚¹æ–‡æ¡ˆï¼ˆåŽå°å­—å…¸ cj_fill_title,匿名可读) ==========
// å¹³å°æ ‡é¢˜/副标题等 â†’ { platformTitle, platformSubtitle, loginSubtitle }
export function getSiteTitles() {
  return r.get('/miniapp/site-titles')
}
// ========== è´¦å·ä½“系(注册/登录/找回/改密) ==========
// å›¾å½¢éªŒè¯ç ï¼šè¿”回 { captchaEnabled, uuid, img(base64) }
export function getCaptcha() {
  return r.get('/miniapp/captcha')
}
// æ³¨å†Œ = ç­çº§ç å»ºæ¡£ï¼ˆå­¦å·+姓名+手机号+密码+验证码),成功即登录
export function accountRegister(data) {
  return r.post('/miniapp/account/register', data)
}
// è´¦å·å¯†ç ç™»å½•(学号+姓名+密码+验证码)→ { token, mustChange }
export function accountLogin(data) {
  return r.post('/miniapp/account/login', data)
}
// å¿˜è®°å¯†ç  = ä¸‰è¦ç´ è‡ªåŠ©é‡ç½®ï¼ˆå­¦å·+姓名+注册时自填手机号+新密码+验证码)
export function accountReset(data) {
  return r.post('/miniapp/account/reset', data)
}
// ä¿®æ”¹å¯†ç ï¼ˆç™»å½•态)→ { token }(新 token,其他设备会话作废)
export function accountChange(data) {
  return r.post('/miniapp/account/change', data)
}
// è§£æžç­çº§æ³¨å†Œç  â†’ { classId, className, majorName, collegeName }(扫码进入注册页时展示班级)
export function resolveBind(bindCode) {
  return r.get('/miniapp/account/resolve', { bindCode })
}
// æ¢ç­ï¼ˆç™»å½•态 + æ–°ç­çº§ç ï¼‰â†’ { className };已提交表单仍归属原班级
export function accountRebind(bindCode) {
  return r.post('/miniapp/account/rebind', { bindCode })
}
// å…¨éƒ¨å¯é€‰ç­çº§ï¼ˆæœªæ‰«ç æ³¨å†Œæ—¶æ‰‹åŠ¨é€‰æ‹©ï¼‰â†’ [{classId, label}]
export function getRegClasses() {
  return r.get('/miniapp/account/classes')
}
src/api/basicData/customerFile.js
ÎļþÒÑɾ³ý
src/api/basicData/product.js
ÎļþÒÑɾ³ý
src/api/basicData/supplierManageFile.js
ÎļþÒÑɾ³ý
src/api/collaborativeApproval/approvalProcess.js
ÎļþÒÑɾ³ý
src/api/collaborativeApproval/attendanceManagement.js
ÎļþÒÑɾ³ý
src/api/collaborativeApproval/knowledgeBase.js
ÎļþÒÑɾ³ý
src/api/collaborativeApproval/noticeManagement.js
ÎļþÒÑɾ³ý
src/api/collaborativeApproval/notificationManagement.js
ÎļþÒÑɾ³ý
src/api/collaborativeApproval/officeSupplies.js
ÎļþÒÑɾ³ý
src/api/collaborativeApproval/planTemplate.js
ÎļþÒÑɾ³ý
src/api/collaborativeApproval/rpaManagement.js
ÎļþÒÑɾ³ý
src/api/collaborativeApproval/sealManagement.js
ÎļþÒÑɾ³ý
src/api/customerService/index.js
ÎļþÒÑɾ³ý
src/api/energyManagement/index.js
ÎļþÒÑɾ³ý
src/api/energyManagement/waterManagement.js
ÎļþÒÑɾ³ý
src/api/equipmentManagement/brand.js
ÎļþÒÑɾ³ý
src/api/equipmentManagement/calibration.js
ÎļþÒÑɾ³ý
src/api/equipmentManagement/deviceInfo.js
ÎļþÒÑɾ³ý
src/api/equipmentManagement/ledger.js
ÎļþÒÑɾ³ý
src/api/equipmentManagement/measurementEquipment.js
ÎļþÒÑɾ³ý
src/api/equipmentManagement/repair.js
ÎļþÒÑɾ³ý
src/api/equipmentManagement/upkeep.js
ÎļþÒÑɾ³ý
src/api/fileManagement/bookshelf.js
ÎļþÒÑɾ³ý
src/api/fileManagement/borrow.js
ÎļþÒÑɾ³ý
src/api/fileManagement/document.js
ÎļþÒÑɾ³ý
src/api/fileManagement/return.js
ÎļþÒÑɾ³ý
src/api/fileManagement/statistics.js
ÎļþÒÑɾ³ý
src/api/financialManagement/expenseManagement.js
ÎļþÒÑɾ³ý
src/api/financialManagement/financialStatements.js
ÎļþÒÑɾ³ý
src/api/financialManagement/revenueManagement.js
ÎļþÒÑɾ³ý
src/api/inventoryManagement/stockIn.js
ÎļþÒÑɾ³ý
src/api/inventoryManagement/stockManage.js
ÎļþÒÑɾ³ý
src/api/inventoryManagement/stockOut.js
ÎļþÒÑɾ³ý
src/api/inventoryManagement/stockWarning.js
ÎļþÒÑɾ³ý
src/api/lavorissce/ledger.js
ÎļþÒÑɾ³ý
src/api/login.js
ÎļþÒÑɾ³ý
src/api/menu.js
ÎļþÒÑɾ³ý
src/api/monitor/cache.js
ÎļþÒÑɾ³ý
src/api/monitor/job.js
ÎļþÒÑɾ³ý
src/api/monitor/jobLog.js
ÎļþÒÑɾ³ý
src/api/monitor/logininfor.js
ÎļþÒÑɾ³ý
src/api/monitor/online.js
ÎļþÒÑɾ³ý
src/api/monitor/operlog.js
ÎļþÒÑɾ³ý
src/api/monitor/server.js
ÎļþÒÑɾ³ý
src/api/personnelManagement/employeeRecord.js
ÎļþÒÑɾ³ý
src/api/personnelManagement/onboarding.js
ÎļþÒÑɾ³ý
src/api/personnelManagement/payrollManagement.js
ÎļþÒÑɾ³ý
src/api/personnelManagement/scheduling.js
ÎļþÒÑɾ³ý
src/api/personnelManagement/selfService.js
ÎļþÒÑɾ³ý
src/api/procurementManagement/invoiceEntry.js
ÎļþÒÑɾ³ý
src/api/procurementManagement/paymentEntry.js
ÎļþÒÑɾ³ý
src/api/procurementManagement/paymentLedger.js
ÎļþÒÑɾ³ý
src/api/procurementManagement/procurementInvoiceLedger.js
ÎļþÒÑɾ³ý
src/api/procurementManagement/procurementLedger.js
ÎļþÒÑɾ³ý
src/api/procurementManagement/projectProfit.js
ÎļþÒÑɾ³ý
src/api/procurementManagement/taxComparison.js
ÎļþÒÑɾ³ý
src/api/productionManagement/operationScheduling.js
ÎļþÒÑɾ³ý
src/api/productionManagement/productionCosting.js
ÎļþÒÑɾ³ý
src/api/productionManagement/productionOrder.js
ÎļþÒÑɾ³ý
src/api/productionManagement/productionReporting.js
ÎļþÒÑɾ³ý
src/api/qualityManagement/metricMaintenance.js
ÎļþÒÑɾ³ý
src/api/qualityManagement/nonconformingManagement.js
ÎļþÒÑɾ³ý
src/api/qualityManagement/qualityInspectFile.js
ÎļþÒÑɾ³ý
src/api/qualityManagement/qualityInspectParam.js
ÎļþÒÑɾ³ý
src/api/qualityManagement/rawMaterialInspection.js
ÎļþÒÑɾ³ý
src/api/salesManagement/invoiceLedger.js
ÎļþÒÑɾ³ý
src/api/salesManagement/invoiceRegistration.js
ÎļþÒÑɾ³ý
src/api/salesManagement/receiptPayment.js
ÎļþÒÑɾ³ý
src/api/salesManagement/salesLedger.js
ÎļþÒÑɾ³ý
src/api/system/config.js
ÎļþÒÑɾ³ý
src/api/system/dept.js
ÎļþÒÑɾ³ý
src/api/system/dict/data.js
ÎļþÒÑɾ³ý
src/api/system/dict/type.js
ÎļþÒÑɾ³ý
src/api/system/menu.js
ÎļþÒÑɾ³ý
src/api/system/notice.js
ÎļþÒÑɾ³ý
src/api/system/post.js
ÎļþÒÑɾ³ý
src/api/system/role.js
ÎļþÒÑɾ³ý
src/api/system/user.js
ÎļþÒÑɾ³ý
src/api/task.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
/**
 * å­¦ç”Ÿç«¯ API:填表任务(动态 schema å¡«æŠ¥ï¼‰
 */
import r from '@/utils/request.js'
// æˆ‘可填报/已填报的任务列表
export function getTasks() {
  return r.get('/miniapp/tasks')
}
// ä»»åŠ¡è¡¨å•ï¼šschema + é¢„å¡« + æˆ‘的记录
export function getTaskForm(taskId) {
  return r.get('/miniapp/task/' + taskId)
}
// ä¿å­˜è‰ç¨¿
export function saveTaskDraft(data) {
  return r.post('/miniapp/task/draft', data)
}
// æ­£å¼æäº¤
export function submitTask(data) {
  return r.post('/miniapp/task/submit', data)
}
src/api/tool/gen.js
ÎļþÒÑɾ³ý
src/api/viewIndex.js
ÎļþÒÑɾ³ý
src/assets/401_images/401.gif
Binary files differ
src/assets/404_images/404.png
Binary files differ
src/assets/404_images/404_cloud.png
Binary files differ
src/assets/fonts/DIN Alternate Bold.ttf
Binary files differ
src/assets/fonts/font.css
ÎļþÒÑɾ³ý
src/assets/icons/png/1.png
Binary files differ
src/assets/icons/png/2.png
Binary files differ
src/assets/icons/png/3.png
Binary files differ
src/assets/icons/png/4.png
Binary files differ
src/assets/icons/png/5.png
Binary files differ
src/assets/icons/png/Ö§³ö.png
Binary files differ
src/assets/icons/png/Ö§³ö½ð¶î.png
Binary files differ
src/assets/icons/png/ÊÕÈëÁÐÕÊ.png
Binary files differ
src/assets/icons/png/ÊÕÈëÊÕ¿î.png
Binary files differ
src/assets/icons/png/ÊÕÈë½ð¶î.png
Binary files differ
src/assets/icons/svg/404.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/bug.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/build.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/button.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/cascader.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/chart.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/checkbox.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/clipboard.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/code.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/color.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/component.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/dashboard.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/date-range.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/date.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/dict.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/documentation.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/download.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/drag.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/druid.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/edit.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/education.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/email.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/example.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/excel.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/exit-fullscreen.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/eye-open.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/eye.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/form.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/fullscreen.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/github.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/guide.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/icon.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/input.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/international.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/job.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/language.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/link.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/list.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/lock.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/log.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/logininfor.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/message.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/money.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/monitor.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/moon.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/nested.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/number.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/online.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/password.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/pdf.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/people.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/peoples.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/phone.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/post.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/qq.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/question.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/radio.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/rate.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/redis-list.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/redis.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/row.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/search.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/select.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/server.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/shopping.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/size.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/skill.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/slider.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/star.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/sunny.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/swagger.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/switch.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/system.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/tab.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/table.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/textarea.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/theme.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/time-range.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/time.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/tool.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/tree-table.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/tree.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/upload.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/user.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/validCode.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/wechat.svg
ÎļþÒÑɾ³ý
src/assets/icons/svg/zip.svg
ÎļþÒÑɾ³ý
src/assets/images/Rectangle 76@2x.png
Binary files differ
src/assets/images/Rectangle 77@2x(1).png
Binary files differ
src/assets/images/Rectangle 77@2x.png
Binary files differ
src/assets/images/caigou.png
Binary files differ
src/assets/images/chuchang.png
Binary files differ
src/assets/images/dark.svg
ÎļþÒÑɾ³ý
src/assets/images/denglu.png
Binary files differ
src/assets/images/guocheng.png
Binary files differ
src/assets/images/icon 3.png
Binary files differ
src/assets/images/icon1.png
Binary files differ
src/assets/images/icon2.png
Binary files differ
src/assets/images/khtitle.png
Binary files differ
src/assets/images/kucun.png
Binary files differ
src/assets/images/light.svg
ÎļþÒÑɾ³ý
src/assets/images/login-background.png
Binary files differ
src/assets/images/pay.png
Binary files differ
src/assets/images/profile.jpg
Binary files differ
src/assets/images/xioashoushuju.png
Binary files differ
src/assets/images/yuancailiao.png
Binary files differ
src/assets/img/emoji/clown-face.png
Binary files differ
src/assets/img/emoji/face-screaming-in-fear.png
Binary files differ
src/assets/img/emoji/face-vomiting.png
Binary files differ
src/assets/img/emoji/face-with-tongue.png
Binary files differ
src/assets/img/emoji/face-without-mouth.png
Binary files differ
src/assets/img/emoji/ghost.png
Binary files differ
src/assets/img/emoji/hibiscus.png
Binary files differ
src/assets/img/emoji/jack-o-lantern.png
Binary files differ
src/assets/img/emoji/lips.png
Binary files differ
src/assets/img/emoji/loudly-crying-face.png
Binary files differ
src/assets/img/emoji/money-bag.png
Binary files differ
src/assets/img/emoji/money-mouth-face.png
Binary files differ
src/assets/img/emoji/new-moon-face.png
Binary files differ
src/assets/img/emoji/ok-hand-yellow.png
Binary files differ
src/assets/img/emoji/pile-of-poo.png
Binary files differ
src/assets/img/emoji/pouting-face.png
Binary files differ
src/assets/img/emoji/rainbow.png
Binary files differ
src/assets/img/emoji/rocket.png
Binary files differ
src/assets/img/emoji/shamrock.png
Binary files differ
src/assets/img/emoji/shangchuan.png
Binary files differ
src/assets/img/emoji/slightly-smiling-face.png
Binary files differ
src/assets/img/emoji/smiling-face-with-heart-eyes.png
Binary files differ
src/assets/img/emoji/smiling-face-with-horns.png
Binary files differ
src/assets/img/emoji/smiling-face-with-sunglasses.png
Binary files differ
src/assets/img/emoji/smiling-face.png
Binary files differ
src/assets/img/emoji/sparkles.png
Binary files differ
src/assets/img/emoji/star.png
Binary files differ
src/assets/img/emoji/thinking-face.png
Binary files differ
src/assets/img/emoji/thought-balloon.png
Binary files differ
src/assets/img/emoji/thumbs-up-yellow.png
Binary files differ
src/assets/img/emoji/tired-face.png
Binary files differ
src/assets/img/emoji/two-hearts.png
Binary files differ
src/assets/img/emoji/victory-hand-yellow.png
Binary files differ
src/assets/img/emoji/È¡Ïû.png
Binary files differ
src/assets/img/fileImg/excel.png
Binary files differ
src/assets/img/fileImg/pdf.png
Binary files differ
src/assets/img/fileImg/ppt.png
Binary files differ
src/assets/img/fileImg/txt.png
Binary files differ
src/assets/img/fileImg/unknowfile.png
Binary files differ
src/assets/img/fileImg/word.png
Binary files differ
src/assets/img/fileImg/zpi.png
Binary files differ
src/assets/img/head_portrait.jpg
Binary files differ
src/assets/img/head_portrait1.png
Binary files differ
src/assets/img/logo.png
Binary files differ
src/assets/indexViews/DHDCLogo.png
Binary files differ
src/assets/indexViews/DHDCView.png
Binary files differ
src/assets/indexViews/HYSNLogo.png
Binary files differ
src/assets/indexViews/HYSNView.png
Binary files differ
src/assets/indexViews/JZYJLogo.png
Binary files differ
src/assets/indexViews/JZYJView.png
Binary files differ
src/assets/indexViews/WDSYLogo.png
Binary files differ
src/assets/indexViews/WDSYView.png
Binary files differ
src/assets/indexViews/ZQHXLogo.png
Binary files differ
src/assets/indexViews/ZQHXView.png
Binary files differ
src/assets/logo/logo.png
Binary files differ
src/assets/logo/ÉϺ£Û«êÅÍøÂç¿Æ¼¼ÓÐÏÞ¹«Ë¾.png
Binary files differ
src/assets/logo/ÄÏÍ¨ÔÆ´Ó¹¤Òµ»¥ÁªÍøÓÐÏÞ¹«Ë¾.png
Binary files differ
src/assets/logo/¶Ø»Í¶¦³Ï.png
Binary files differ
src/assets/logo/ÐÂÀ£¨½­ËÕ£©Êý×ֿƼ¼ÓÐÏÞ¹«Ë¾.png
Binary files differ
src/assets/logo/оµ¼Èí¼þ£¨½­ËÕ£©ÓÐÏÞ¹«Ë¾.png
Binary files differ
src/assets/styles/btn.scss
ÎļþÒÑɾ³ý
src/assets/styles/element-ui.scss
ÎļþÒÑɾ³ý
src/assets/styles/index.scss
ÎļþÒÑɾ³ý
src/assets/styles/mixin.scss
ÎļþÒÑɾ³ý
src/assets/styles/ruoyi.scss
ÎļþÒÑɾ³ý
src/assets/styles/sidebar.scss
ÎļþÒÑɾ³ý
src/assets/styles/transition.scss
ÎļþÒÑɾ³ý
src/assets/styles/variables.module.scss
ÎļþÒÑɾ³ý
src/components/Breadcrumb/index.vue
ÎļþÒÑɾ³ý
src/components/Crontab/day.vue
ÎļþÒÑɾ³ý
src/components/Crontab/hour.vue
ÎļþÒÑɾ³ý
src/components/Crontab/index.vue
ÎļþÒÑɾ³ý
src/components/Crontab/min.vue
ÎļþÒÑɾ³ý
src/components/Crontab/month.vue
ÎļþÒÑɾ³ý
src/components/Crontab/result.vue
ÎļþÒÑɾ³ý
src/components/Crontab/second.vue
ÎļþÒÑɾ³ý
src/components/Crontab/week.vue
ÎļþÒÑɾ³ý
src/components/Crontab/year.vue
ÎļþÒÑɾ³ý
src/components/DictTag/index.vue
ÎļþÒÑɾ³ý
src/components/DynamicTable/index.vue
ÎļþÒÑɾ³ý
src/components/Echarts/echarts.vue
ÎļþÒÑɾ³ý
src/components/Editor/index.vue
ÎļþÒÑɾ³ý
src/components/FileCard.vue
ÎļþÒÑɾ³ý
src/components/FileUpload/index.vue
ÎļþÒÑɾ³ý
src/components/Hamburger/index.vue
ÎļþÒÑɾ³ý
src/components/HeaderSearch/index.vue
ÎļþÒÑɾ³ý
src/components/IconSelect/index.vue
ÎļþÒÑɾ³ý
src/components/IconSelect/requireIcons.js
ÎļþÒÑɾ³ý
src/components/ImagePreview/index.vue
ÎļþÒÑɾ³ý
src/components/ImageUpload/index.vue
ÎļþÒÑɾ³ý
src/components/PIMTable/PIMTable.vue
ÎļþÒÑɾ³ý
src/components/PIMTable/Pagination.vue
ÎļþÒÑɾ³ý
src/components/Pagination/index.vue
ÎļþÒÑɾ³ý
src/components/ParentView/index.vue
ÎļþÒÑɾ³ý
src/components/QRCodeGenerator/index.vue
ÎļþÒÑɾ³ý
src/components/RightToolbar/index.vue
ÎļþÒÑɾ³ý
src/components/RuoYi/Doc/index.vue
ÎļþÒÑɾ³ý
src/components/RuoYi/Git/index.vue
ÎļþÒÑɾ³ý
src/components/Screenfull/index.vue
ÎļþÒÑɾ³ý
src/components/SizeSelect/index.vue
ÎļþÒÑɾ³ý
src/components/SvgIcon/index.vue
ÎļþÒÑɾ³ý
src/components/SvgIcon/svgicon.js
ÎļþÒÑɾ³ý
src/components/TopNav/index.vue
ÎļþÒÑɾ³ý
src/components/Upload/FileUpload.vue
ÎļþÒÑɾ³ý
src/components/Upload/index.js
ÎļþÒÑɾ³ý
src/components/filePreview/index.vue
ÎļþÒÑɾ³ý
src/components/iFrame/index.vue
ÎļþÒÑɾ³ý
src/config.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
/**
 * å­¦ç”Ÿç«¯å…¨å±€é…ç½®
 * é€šè¿‡ manifest.json çš„ H5 çŽ¯å¢ƒå˜é‡æˆ–ç›´æŽ¥ä¿®æ”¹æ­¤å¤„
 */
export default {
  // åŽç«¯æŽ¥å£åœ°å€
  // å¼€å‘ H5(本机后端): http://localhost:8080
  // ç”Ÿäº§ï¼ˆæ­£å¼åŸŸå/服务器): http://your-domain.com/dev-api æˆ– https://...
  baseUrl: '/prod-api', // ç”Ÿäº§ï¼šèµ° nginx ä»£ç†ï¼ˆåŒæºï¼Œé¿å…è·¨åŸŸï¼‰
  // å¾®ä¿¡å°ç¨‹åº AppID(配置于 manifest.json mp-weixin.appid)
  appName: '产教融合实践教学管理平台',
}
src/directive/common/copyText.js
ÎļþÒÑɾ³ý
src/directive/index.js
ÎļþÒÑɾ³ý
src/directive/permission/hasPermi.js
ÎļþÒÑɾ³ý
src/directive/permission/hasRole.js
ÎļþÒÑɾ³ý
src/hooks/useFormData.js
ÎļþÒÑɾ³ý
src/hooks/useModal.js
ÎļþÒÑɾ³ý
src/hooks/usePaginationApi.jsx
ÎļþÒÑɾ³ý
src/layout/components/AppMain.vue
ÎļþÒÑɾ³ý
src/layout/components/IframeToggle/index.vue
ÎļþÒÑɾ³ý
src/layout/components/InnerLink/index.vue
ÎļþÒÑɾ³ý
src/layout/components/Navbar.vue
ÎļþÒÑɾ³ý
src/layout/components/Settings/index.vue
ÎļþÒÑɾ³ý
src/layout/components/Sidebar/Link.vue
ÎļþÒÑɾ³ý
src/layout/components/Sidebar/Logo.vue
ÎļþÒÑɾ³ý
src/layout/components/Sidebar/SidebarItem.vue
ÎļþÒÑɾ³ý
src/layout/components/Sidebar/index.vue
ÎļþÒÑɾ³ý
src/layout/components/TagsView/ScrollPane.vue
ÎļþÒÑɾ³ý
src/layout/components/TagsView/index.vue
ÎļþÒÑɾ³ý
src/layout/components/index.js
ÎļþÒÑɾ³ý
src/layout/index.vue
ÎļþÒÑɾ³ý
src/main.js
@@ -1,113 +1,10 @@
import { createApp } from "vue";
import Cookies from "js-cookie";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
import "element-plus/theme-chalk/dark/css-vars.css";
import locale from "element-plus/es/locale/lang/zh-cn";
import "@/assets/styles/index.scss"; // global css
import App from "./App";
import store from "./store";
import router from "./router";
import directive from "./directive"; // directive
// æ³¨å†ŒæŒ‡ä»¤
import plugins from "./plugins"; // plugins
import { download } from "@/utils/request";
// svg图标
import "virtual:svg-icons-register";
import SvgIcon from "@/components/SvgIcon";
import elementIcons from "@/components/SvgIcon/svgicon";
import "./assets/fonts/font.css";
import "./permission"; // permission control
import { useDict } from "@/utils/dict";
import {
  parseTime,
  resetForm,
  addDateRange,
  handleTree,
  selectDictLabel,
  selectDictLabels,
} from "@/utils/ruoyi";
// åˆ†é¡µç»„ä»¶
import Pagination from "@/components/Pagination";
// è‡ªå®šä¹‰è¡¨æ ¼å·¥å…·ç»„ä»¶
import RightToolbar from "@/components/RightToolbar";
// å¯Œæ–‡æœ¬ç»„ä»¶
import Editor from "@/components/Editor";
// æ–‡ä»¶ä¸Šä¼ ç»„ä»¶
import FileUpload from "@/components/FileUpload";
// å›¾ç‰‡ä¸Šä¼ ç»„ä»¶
import ImageUpload from "@/components/ImageUpload";
// å›¾ç‰‡é¢„览组件
import ImagePreview from "@/components/ImagePreview";
// å­—典标签组件
import DictTag from "@/components/DictTag";
// è¡¨æ ¼ç»„ä»¶
import PIMTable from "@/components/PIMTable/PIMTable.vue";
import { getToken } from "@/utils/auth";
import {
  calculateTaxExclusiveTotalPrice,
  summarizeTable,
  calculateTaxIncludeTotalPrice,
} from "@/utils/summarizeTable.js";
const app = createApp(App);
// å…¨å±€æ–¹æ³•挂载
app.config.globalProperties.useDict = useDict;
app.config.globalProperties.download = download;
app.config.globalProperties.parseTime = parseTime;
app.config.globalProperties.resetForm = resetForm;
app.config.globalProperties.summarizeTable = summarizeTable;
app.config.globalProperties.calculateTaxExclusiveTotalPrice =
  calculateTaxExclusiveTotalPrice;
app.config.globalProperties.calculateTaxIncludeTotalPrice =
  calculateTaxIncludeTotalPrice;
app.config.globalProperties.handleTree = handleTree;
app.config.globalProperties.addDateRange = addDateRange;
app.config.globalProperties.selectDictLabel = selectDictLabel;
app.config.globalProperties.selectDictLabels = selectDictLabels;
app.config.globalProperties.javaApi = "http://114.132.189.42:9033";
app.config.globalProperties.HaveJson = (val) => {
  return JSON.parse(JSON.stringify(val));
};
app.config.globalProperties.uploadHeader = {
  Authorization: "Bearer " + getToken(),
};
// å…¨å±€ç»„件挂载
app.component("DictTag", DictTag);
app.component("Pagination", Pagination);
app.component("FileUpload", FileUpload);
app.component("ImageUpload", ImageUpload);
app.component("ImagePreview", ImagePreview);
app.component("RightToolbar", RightToolbar);
app.component("Editor", Editor);
app.component("PIMTable", PIMTable);
app.use(router);
app.use(store);
app.use(plugins);
app.use(elementIcons);
app.component("svg-icon", SvgIcon);
directive(app);
// ä½¿ç”¨element-plus å¹¶ä¸”设置全局的大小
app.use(ElementPlus, {
  locale: locale,
  // æ”¯æŒ large、default、small
  size: Cookies.get("size") || "default",
});
app._context.components.ElDialog.props.closeOnClickModal.default = false;
app.mount("#app");
    createSSRApp
} from "vue";
import App from "./App.vue";
export function createApp() {
    const app = createSSRApp(App);
    return {
        app,
    };
}
src/manifest.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,72 @@
{
    "name" : "",
    "appid" : "",
    "description" : "",
    "versionName" : "1.0.0",
    "versionCode" : "100",
    "transformPx" : false,
    /* 5+App特有相关 */
    "app-plus" : {
        "usingComponents" : true,
        "nvueStyleCompiler" : "uni-app",
        "compilerVersion" : 3,
        "splashscreen" : {
            "alwaysShowBeforeRender" : true,
            "waiting" : true,
            "autoclose" : true,
            "delay" : 0
        },
        /* æ¨¡å—配置 */
        "modules" : {},
        /* åº”用发布信息 */
        "distribute" : {
            /* android打包配置 */
            "android" : {
                "permissions" : [
                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
                    "<uses-feature android:name=\"android.hardware.camera\"/>",
                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
                ]
            },
            /* ios打包配置 */
            "ios" : {},
            /* SDK配置 */
            "sdkConfigs" : {}
        }
    },
    /* å¿«åº”用特有相关 */
    "quickapp" : {},
    /* å°ç¨‹åºç‰¹æœ‰ç›¸å…³ */
    "mp-weixin" : {
        "appid" : "wxc52c6347b57afd4b",
        "setting" : {
            "urlCheck" : false
        },
        "usingComponents" : true
    },
    "mp-alipay" : {
        "usingComponents" : true
    },
    "mp-baidu" : {
        "usingComponents" : true
    },
    "mp-toutiao" : {
        "usingComponents" : true
    },
    "uniStatistics": {
        "enable": false
    },
    "vueVersion" : "3"
}
src/pages.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,46 @@
{
    "pages": [
        {
            "path": "pages/index/index",
            "style": {
                "navigationBarTitleText": "产教融合实践教学管理平台"
            }
        },
{
            "path": "pages/plan/form",
            "style": {
                "navigationBarTitleText": "信息填报"
            }
        },
        {
            "path": "pages/login/login",
            "style": {
                "navigationBarTitleText": "登录"
            }
        },
        {
            "path": "pages/register/register",
            "style": {
                "navigationBarTitleText": "注册账号"
            }
        },
        {
            "path": "pages/forgot/forgot",
            "style": {
                "navigationBarTitleText": "忘记密码"
            }
        },
        {
            "path": "pages/password/change",
            "style": {
                "navigationBarTitleText": "修改密码"
            }
        }
    ],
    "globalStyle": {
        "navigationBarTextStyle": "white",
        "navigationBarTitleText": "产教融合实践教学管理平台",
        "navigationBarBackgroundColor": "#1F4788",
        "backgroundColor": "#EEF2F8"
    }
}
src/pages/forgot/forgot.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,170 @@
<template>
  <view class="page">
    <view class="brand">
      <image class="brand-watermark" src="/static/logo-emblem-white.png" mode="aspectFit" />
      <image class="brand-logo" src="/static/logo-head-white.png" mode="aspectFit" />
      <view class="brand-title">忘记密码</view>
      <view class="brand-sub">用注册时填写的“学号 + å§“名 + æ‰‹æœºå·â€è‡ªåŠ©é‡ç½®ï¼›ä¸ä¸€è‡´è¯·è”ç³»ç­ä¸»ä»»</view>
    </view>
    <view class="card">
      <view class="field" :class="{ 'field-err': errors.studentNo }">
        <text class="label">学号</text>
        <input class="input" v-model="form.studentNo" placeholder="请输入学号" placeholder-class="ph" @input="clearErr('studentNo')" />
        <view v-if="errors.studentNo" class="err-text">{{ errors.studentNo }}</view>
      </view>
      <view class="field" :class="{ 'field-err': errors.name }">
        <text class="label">姓名</text>
        <input class="input" v-model="form.name" placeholder="请输入姓名" placeholder-class="ph" @input="clearErr('name')" />
        <view v-if="errors.name" class="err-text">{{ errors.name }}</view>
      </view>
      <view class="field" :class="{ 'field-err': errors.phone }">
        <text class="label">注册手机号</text>
        <input class="input" v-model="form.phone" type="number" maxlength="11" placeholder="注册时填写的手机号" placeholder-class="ph" @input="clearErr('phone')" />
        <view v-if="errors.phone" class="err-text">{{ errors.phone }}</view>
      </view>
      <view class="field" :class="{ 'field-err': errors.password }">
        <text class="label">新密码</text>
        <input class="input" v-model="form.password" type="password" placeholder="8-20位,须含字母和数字" placeholder-class="ph" @input="clearErr('password')" />
        <view v-if="errors.password" class="err-text">{{ errors.password }}</view>
      </view>
      <view class="field" :class="{ 'field-err': errors.confirm }">
        <text class="label">确认新密码</text>
        <input class="input" v-model="form.confirm" type="password" placeholder="请再次输入新密码" placeholder-class="ph" @input="clearErr('confirm')" />
        <view v-if="errors.confirm" class="err-text">{{ errors.confirm }}</view>
      </view>
      <view class="field" v-if="captchaEnabled" :class="{ 'field-err': errors.code }">
        <text class="label">验证码</text>
        <view class="captcha-row">
          <input class="input captcha-input" v-model="form.code" placeholder="请输入验证码" placeholder-class="ph" maxlength="6" @input="clearErr('code')" />
          <image class="captcha-img" :src="captchaImg" mode="aspectFit" @click="loadCaptcha" />
        </view>
        <view v-if="errors.code" class="err-text">{{ errors.code }}</view>
      </view>
      <button class="btn btn-primary btn-block" :loading="submitting" :disabled="submitting" @click="doReset">
        {{ submitting ? '提交中…' : '重置密码' }}
      </button>
      <view class="links">
        <text class="link" @click="go('/pages/login/login')">返回登录</text>
      </view>
      <view class="tip">重置成功后原登录状态会在所有设备失效;10 åˆ†é’Ÿå†…最多尝试 3 æ¬¡</view>
    </view>
  </view>
</template>
<script>
import { getCaptcha, accountReset } from '@/api/auth.js'
import { clearToken } from '@/utils/request.js'
export default {
  data() {
    return {
      submitting: false,
      form: { studentNo: '', name: '', phone: '', password: '', confirm: '', code: '', uuid: '' },
      errors: {},
      captchaEnabled: true,
      captchaImg: '',
    }
  },
  onLoad() { this.loadCaptcha() },
  methods: {
    async loadCaptcha() {
      try {
        const res = await getCaptcha()
        this.captchaEnabled = res.captchaEnabled !== false
        this.captchaImg = res.img ? 'data:image/jpg;base64,' + res.img : ''
        this.form.uuid = res.uuid || ''
        this.form.code = ''
      } catch (e) { /* ignore */ }
    },
    clearErr(k) { if (this.errors[k]) delete this.errors[k] },
    validate() {
      const errs = {}
      if (!this.form.studentNo.trim()) errs.studentNo = '请输入学号'
      if (!this.form.name.trim()) errs.name = '请输入姓名'
      if (!/^1[3-9]\d{9}$/.test(this.form.phone)) errs.phone = '请输入11位手机号'
      const p = this.form.password
      if (!p) errs.password = '请输入新密码'
      else if (!/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d!@#$%^&*_.\-+=?]{8,20}$/.test(p)) errs.password = '8-20位,须同时包含字母和数字'
      else if (p === this.form.studentNo.trim()) errs.password = '密码不能与学号相同'
      if (this.form.confirm !== p) errs.confirm = '两次输入的密码不一致'
      if (this.captchaEnabled && !this.form.code.trim()) errs.code = '请输入验证码'
      this.errors = errs
      return !Object.keys(errs).length
    },
    async doReset() {
      if (!this.validate()) return
      this.submitting = true
      try {
        await accountReset({
          studentNo: this.form.studentNo.trim(),
          name: this.form.name.trim(),
          phone: this.form.phone.trim(),
          newPassword: this.form.password,
          code: this.form.code.trim(),
          uuid: this.form.uuid,
        })
        clearToken() // æ—§ä¼šè¯å·²è¢«æœåŠ¡ç«¯ä½œåºŸï¼Œæœ¬åœ° token ä¸€å¹¶æ¸…掉
        uni.showToast({ title: '重置成功,请登录', icon: 'success' })
        setTimeout(() => uni.redirectTo({ url: '/pages/login/login' }), 800)
      } catch (e) {
        if (this.captchaEnabled) this.loadCaptcha()
      } finally {
        this.submitting = false
      }
    },
    go(url) { uni.navigateTo({ url }) },
  },
}
</script>
<style scoped>
button { margin: 0; padding: 0; }
button::after { border: none; }
.page { min-height: 100vh; background: #EEF2F8; padding: 0 0 60rpx; box-sizing: border-box; }
.brand {
  position: relative;
  padding: 48rpx 44rpx 96rpx;
  overflow: hidden;
  background:
    radial-gradient(420rpx 260rpx at 88% -20%, rgba(120, 165, 225, 0.38), transparent 60%),
    linear-gradient(135deg, #16345e 0%, #1F4788 55%, #2a5aa8 100%);
  border-radius: 0 0 30rpx 30rpx;
}
.brand-watermark { position: absolute; right: -36rpx; bottom: -60rpx; width: 280rpx; height: 280rpx; opacity: 0.12; }
.brand-logo { width: 380rpx; height: 84rpx; display: block; }
.brand-title { position: relative; margin-top: 26rpx; font-size: 40rpx; font-weight: 700; color: #fff; letter-spacing: 8rpx; }
.brand-sub { position: relative; margin-top: 10rpx; font-size: 24rpx; color: rgba(255, 255, 255, 0.72); line-height: 1.5; }
.card { position: relative; z-index: 1; background: #fff; margin: -56rpx 24rpx 0; border-radius: 16rpx; padding: 40rpx 30rpx 44rpx; box-shadow: 0 12rpx 36rpx rgba(31, 71, 136, 0.12); }
.field { margin-bottom: 28rpx; }
.label { display: block; font-size: 27rpx; color: #303133; margin-bottom: 12rpx; }
.field-err .label { color: #C03; }
.input { height: 88rpx; line-height: 88rpx; background: #fff; border: 1rpx solid #DCDFE6; border-radius: 8rpx; padding: 0 22rpx; font-size: 29rpx; color: #1F2D3D; }
.input.err, .field-err .input { border-color: #E5484D; background: #FDF3F3; }
.err-text { margin-top: 8rpx; color: #E5484D; font-size: 24rpx; }
.ph { color: #C0C4CC; }
.captcha-row { display: flex; align-items: center; }
.captcha-input { flex: 1; }
.captcha-img { width: 200rpx; height: 88rpx; margin-left: 20rpx; border: 1rpx solid #DCDFE6; border-radius: 8rpx; background: #F0F2F6; }
.btn { height: 88rpx; line-height: 88rpx; border-radius: 12rpx; font-size: 30rpx; letter-spacing: 4rpx; text-align: center; box-sizing: border-box; }
.btn-primary { background: linear-gradient(90deg, #16345e, #1F4788 55%, #2a5aa8); color: #fff; box-shadow: 0 8rpx 20rpx rgba(31, 71, 136, 0.28); }
.btn-block { width: 100%; }
.btn[disabled] { opacity: .6; }
.btn-primary[disabled] { color: #fff; }
.links { display: flex; justify-content: center; margin-top: 26rpx; }
.link { color: #1F4788; font-size: 26rpx; }
.tip { margin-top: 20rpx; text-align: center; font-size: 23rpx; color: #B4BAC6; }
</style>
src/pages/index/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,259 @@
<template>
  <view class="page">
    <!-- æœªç™»å½• -->
    <view v-if="!loading && !student">
      <view class="brand">
        <image class="brand-watermark" src="/static/logo-emblem-white.png" mode="aspectFit" />
        <image class="brand-logo" src="/static/logo-head-white.png" mode="aspectFit" />
        <view class="brand-title">{{ titles.platformTitle }}</view>
        <view class="brand-sub">{{ titles.platformSubtitle }}</view>
      </view>
      <view class="login-card">
        <button class="btn btn-primary btn-block" @click="goLogin">登录并填报</button>
        <view class="login-links">
          <text class="link" @click="goRegister">注册账号</text>
        </view>
        <view class="login-tip">推荐扫班主任发的班级二维码注册(自动带入班级);无二维码也可注册时手动选班</view>
      </view>
    </view>
    <!-- å·²ç™»å½• -->
    <block v-else-if="student">
      <!-- è´¦å·å¼•导条 -->
      <view v-if="!student.hasPassword" class="notice" @click="goRegister">
        è´¦å·å®‰å…¨ï¼šä½ è¿˜æœªè®¾ç½®ç™»å½•密码,点击设置 â†’
      </view>
      <view v-else-if="student.mustChangePwd" class="notice notice-warn" @click="goChangePwd">
        å¯†ç å·²è¢«ç®¡ç†å‘˜é‡ç½®ï¼Œè¯·ç«‹å³ä¿®æ”¹ä¸ºä½ è‡ªå·±çš„密码 â†’
      </view>
      <view class="profile">
        <image class="profile-badge" src="/static/logo-emblem-white.png" mode="aspectFit" />
        <view class="profile-main">
          <view class="profile-name">{{ student.name }}
            <text class="profile-no">{{ student.studentNo }}</text>
          </view>
          <view class="profile-org">{{ student.collegeName }} Â· {{ student.className }}</view>
        </view>
        <view class="profile-ops">
          <view class="p-link" @click="goChangePwd">修改密码</view>
          <view class="p-link p-link-plain" @click="doLogout">退出登录</view>
        </view>
      </view>
      <view class="section">
        <view class="section-title">我的填报任务</view>
        <view v-if="loadingTasks" class="state">加载中…</view>
        <view v-else-if="!tasks.length" class="state">
          <text>暂无可填报的任务</text>
          <text class="state-sub">请关注学校发布的填报通知</text>
        </view>
        <view v-else class="task-list">
          <view class="task" v-for="t in tasks" :key="t.taskId" @click="openTask(t)">
            <view class="task-top">
              <text class="task-name">{{ t.taskName }}</text>
              <text class="task-status" :class="statusClass(t)">{{ statusText(t) }}</text>
            </view>
            <view class="task-meta">填报时间:{{ t.fillStartDate }} ~ {{ t.fillEndDate }}</view>
            <view class="task-meta" v-if="t.recordStatus === '1'">提交时间:{{ t.submitTime }}</view>
            <view class="task-op">{{ opText(t) }}</view>
          </view>
        </view>
      </view>
      <view class="footer">如有问题请联系班级管理人</view>
    </block>
    <view v-else class="state">加载中…</view>
  </view>
</template>
<script>
import { getStudentInfo, resolveBind, accountRebind } from '@/api/auth.js'
import { getTasks } from '@/api/task.js'
import { clearToken } from '@/utils/request.js'
import { getTitles, DEFAULT_TITLES } from '@/utils/site.js'
const BIND_CODE_KEY = '***'
export default {
  data() {
    return { loading: true, student: null, tasks: [], loadingTasks: false, rebinding: false, titles: DEFAULT_TITLES }
  },
  // ç­çº§äºŒç»´ç  URL:/#/?c=注册码 â€”— æ•获后:未登录→注册用;已登录→换班确认
  onLoad(options) {
    const c = options && options.c
    if (c) uni.setStorageSync(BIND_CODE_KEY, String(c).trim())
    this.loadTitles()
  },
  onShow() { this.checkLogin() },
  methods: {
    async loadTitles() {
      this.titles = await getTitles()
    },
    async checkLogin() {
      this.loading = true
      const token = uni.getStorageSync('cj_student_token')
      if (token) {
        try {
          const res = await getStudentInfo()
          this.student = res.data
          this.loadTasks()
          this.maybeRebind()
        } catch (e) { this.student = null }
      }
      this.loading = false
    },
    /** å·²ç™»å½•学生扫了新班级码 â†’ æ¢ç­ç¡®è®¤ï¼ˆå·²æäº¤è¡¨å•保留原班级归属) */
    async maybeRebind() {
      const code = uni.getStorageSync(BIND_CODE_KEY)
      if (!code || !this.student || this.rebinding) return
      this.rebinding = true
      try {
        const r = await resolveBind(code)
        const cls = r.data || {}
        if (cls.className && cls.className !== this.student.className) {
          uni.showModal({
            title: '申请换班',
            content: `你当前在"${this.student.className}",扫码班级为"${cls.collegeName || ''} ${cls.majorName || ''} ${cls.className}"。确认换班?(此前已提交的表单仍归属原班级)`,
            confirmText: '确认换班',
            cancelText: '留在原班',
            success: async (m) => {
              if (m.confirm) {
                try {
                  await accountRebind(code)
                  uni.showToast({ title: '换班成功', icon: 'success' })
                  this.checkLogin()
                } catch (e) { /* request.js å·²å¼¹é”™ */ }
              }
            },
          })
        }
      } catch (e) { /* ç æ— æ•ˆåˆ™å¿½ç•¥ */ }
      uni.removeStorageSync(BIND_CODE_KEY)
      this.rebinding = false
    },
    async loadTasks() {
      this.loadingTasks = true
      try {
        const res = await getTasks()
        this.tasks = (res.data && res.data.tasks) || []
      } catch (e) { this.tasks = [] }
      this.loadingTasks = false
    },
    goLogin() { uni.navigateTo({ url: '/pages/login/login' }) },
    goRegister() { uni.navigateTo({ url: '/pages/register/register' }) },
    goChangePwd() { uni.navigateTo({ url: '/pages/password/change' }) },
    openTask(t) { uni.navigateTo({ url: '/pages/plan/form?taskId=' + t.taskId }) },
    doLogout() {
      clearToken()
      // å…¼å®¹æ¸…理旧版 H5 â€œå‡è®¾å¤‡ç â€ç¼“存(该机制已下线)
      uni.removeStorageSync('cj_h5_dev_code')
      this.student = null
      this.tasks = []
      uni.reLaunch({ url: '/pages/login/login' })
    },
    statusText(t) {
      if (t.recordStatus === '1') return '已提交'
      if (t.recordStatus === '0') return '草稿'
      return t.open ? '待填写' : '未开放'
    },
    statusClass(t) {
      if (t.recordStatus === '1') return 'st-ok'
      if (t.recordStatus === '0') return 'st-draft'
      return t.open ? 'st-todo' : 'st-off'
    },
    opText(t) {
      if (t.recordStatus === '1') return '查看填报内容'
      if (t.recordStatus === '0') return '继续填写'
      return '立即填写'
    },
  },
}
</script>
<style scoped>
/* æŒ‰é’®é»˜è®¤æ ·å¼æ”¶æ•›ï¼Œé¿å…è¾¹æ¡†/间距异常 */
button { margin: 0; padding: 0; background: none; }
button::after { border: none; }
.btn { height: 92rpx; line-height: 92rpx; border-radius: 12rpx; font-size: 30rpx; letter-spacing: 4rpx; text-align: center; box-sizing: border-box; }
.btn-primary { background: linear-gradient(90deg, #16345e, #1F4788 55%, #2a5aa8); color: #fff; box-shadow: 0 8rpx 20rpx rgba(31, 71, 136, 0.28); }
.btn-block { width: 100%; }
.btn[disabled] { opacity: .6; color: #fff; }
.page { min-height: 100vh; background: #EEF2F8; padding: 0 0 60rpx; box-sizing: border-box; }
/* å“ç‰Œå¤´å¹… */
.brand {
  position: relative;
  padding: 56rpx 44rpx 110rpx;
  overflow: hidden;
  background:
    radial-gradient(420rpx 260rpx at 88% -20%, rgba(120, 165, 225, 0.38), transparent 60%),
    linear-gradient(135deg, #16345e 0%, #1F4788 55%, #2a5aa8 100%);
  border-radius: 0 0 30rpx 30rpx;
}
.brand-watermark { position: absolute; right: -36rpx; bottom: -60rpx; width: 300rpx; height: 300rpx; opacity: 0.12; }
.brand-logo { width: 380rpx; height: 84rpx; display: block; }
.brand-title { position: relative; margin-top: 26rpx; font-size: 38rpx; font-weight: 700; color: #fff; letter-spacing: 4rpx; }
.brand-sub { position: relative; margin-top: 10rpx; font-size: 24rpx; color: rgba(255, 255, 255, 0.72); line-height: 1.5; }
/* æœªç™»å½•卡片 */
.login-card {
  position: relative;
  z-index: 1;
  background: #fff;
  margin: -64rpx 24rpx 0;
  border-radius: 16rpx;
  padding: 44rpx 34rpx;
  box-shadow: 0 12rpx 36rpx rgba(31, 71, 136, 0.12);
}
.login-links { margin-top: 30rpx; display: flex; justify-content: center; gap: 60rpx; }
.login-tip { margin-top: 24rpx; font-size: 24rpx; color: #B4BAC6; text-align: center; line-height: 1.5; }
/* è´¦å·å¼•导条 */
.notice { background: #E8EFF9; color: #1F4788; border: 1rpx solid #D5E2F5; border-radius: 12rpx; padding: 20rpx 24rpx; font-size: 25rpx; margin: 24rpx 24rpx 0; }
.notice-warn { background: #FBF4E2; color: #B36A00; border-color: #F2E2BC; }
/* ä¸ªäººæ¡ï¼ˆæ·±è“å“ç‰Œå¡ï¼‰ */
.profile {
  margin: 24rpx 24rpx 0;
  background:
    radial-gradient(320rpx 200rpx at 92% -30%, rgba(120, 165, 225, 0.4), transparent 60%),
    linear-gradient(135deg, #16345e 0%, #1F4788 60%, #2a5aa8 100%);
  border-radius: 16rpx;
  padding: 30rpx 28rpx;
  display: flex;
  align-items: center;
  box-shadow: 0 10rpx 30rpx rgba(31, 71, 136, 0.25);
}
.profile-badge { width: 88rpx; height: 88rpx; border-radius: 50%; background: rgba(255, 255, 255, 0.14); padding: 12rpx; flex-shrink: 0; box-sizing: content-box; }
.profile-main { flex: 1; margin-left: 24rpx; min-width: 0; }
.profile-name { font-size: 32rpx; font-weight: 600; color: #fff; }
.profile-no { margin-left: 16rpx; font-size: 24rpx; color: rgba(255, 255, 255, 0.72); font-weight: 400; }
.profile-org { margin-top: 10rpx; font-size: 24rpx; color: rgba(255, 255, 255, 0.72); }
.profile-ops { display: flex; flex-direction: column; align-items: flex-end; gap: 14rpx; flex-shrink: 0; }
.p-link { color: #fff; font-size: 24rpx; padding: 8rpx 22rpx; border: 1rpx solid rgba(255, 255, 255, 0.55); border-radius: 999rpx; }
.p-link-plain { color: rgba(255, 255, 255, 0.78); border-color: rgba(255, 255, 255, 0.3); }
.link { color: #1F4788; font-size: 26rpx; }
.link-plain { color: #7C8698; }
/* åˆ—表 */
.section { margin: 28rpx 24rpx 0; }
.section-title { font-size: 30rpx; font-weight: 600; color: #1F2D3D; padding: 0 4rpx 14rpx; position: relative; padding-left: 20rpx; }
.section-title::before { content: ''; position: absolute; left: 0; top: 8rpx; bottom: 22rpx; width: 8rpx; border-radius: 4rpx; background: linear-gradient(#1F4788, #2a5aa8); }
.state { background: #fff; border-radius: 12rpx; padding: 90rpx 0; text-align: center; color: #8A94A6; font-size: 27rpx; border: 1rpx solid #EBEDF1; }
.state-sub { display: block; margin-top: 10rpx; font-size: 24rpx; color: #B4BAC6; }
.task { background: #fff; border: 1rpx solid #EBEDF1; border-radius: 16rpx; padding: 26rpx 26rpx; margin-bottom: 18rpx; box-shadow: 0 4rpx 14rpx rgba(31, 71, 136, 0.05); }
.task:active { background: #F7F9FC; }
.task-top { display: flex; justify-content: space-between; align-items: flex-start; }
.task-name { flex: 1; font-size: 29rpx; font-weight: 600; color: #1F2D3D; line-height: 1.4; }
.task-status { margin-left: 16rpx; font-size: 22rpx; padding: 2rpx 12rpx; border-radius: 6rpx; flex-shrink: 0; }
.st-ok { color: #1D9D5F; background: #EAF7F0; }
.st-draft { color: #B36A00; background: #FBF4E2; }
.st-todo { color: #1F4788; background: #E8EFF9; }
.st-off { color: #7C8698; background: #F0F2F6; }
.task-meta { margin-top: 12rpx; font-size: 24rpx; color: #7C8698; }
.task-op { margin-top: 16rpx; padding-top: 14rpx; border-top: 1rpx solid #F2F3F6; color: #1F4788; font-weight: 600; font-size: 27rpx; }
.footer { text-align: center; margin-top: 36rpx; font-size: 22rpx; color: #B4BAC6; }
</style>
src/pages/login/login.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,166 @@
<template>
  <view class="page">
    <view class="brand">
      <image class="brand-watermark" src="/static/logo-emblem-white.png" mode="aspectFit" />
      <image class="brand-logo" src="/static/logo-head-white.png" mode="aspectFit" />
      <view class="brand-title">登 å½•</view>
      <view class="brand-sub">{{ titles.loginSubtitle }}</view>
    </view>
    <view class="card">
      <view class="field" :class="{ 'field-err': errors.studentNo }">
        <text class="label">学号</text>
        <input class="input" v-model="form.studentNo" placeholder="请输入学号" placeholder-class="ph" @input="clearErr('studentNo')" />
        <view v-if="errors.studentNo" class="err-text">{{ errors.studentNo }}</view>
      </view>
      <view class="field" :class="{ 'field-err': errors.name }">
        <text class="label">姓名</text>
        <input class="input" v-model="form.name" placeholder="请输入姓名" placeholder-class="ph" @input="clearErr('name')" />
        <view v-if="errors.name" class="err-text">{{ errors.name }}</view>
      </view>
      <view class="field" :class="{ 'field-err': errors.password }">
        <text class="label">密码</text>
        <input class="input" v-model="form.password" type="password" placeholder="请输入密码" placeholder-class="ph" @input="clearErr('password')" />
        <view v-if="errors.password" class="err-text">{{ errors.password }}</view>
      </view>
      <view class="field" v-if="captchaEnabled" :class="{ 'field-err': errors.code }">
        <text class="label">验证码</text>
        <view class="captcha-row">
          <input class="input captcha-input" v-model="form.code" placeholder="请输入验证码" placeholder-class="ph" maxlength="6" @input="clearErr('code')" />
          <image class="captcha-img" :src="captchaImg" mode="aspectFit" @click="loadCaptcha" />
        </view>
        <view v-if="errors.code" class="err-text">{{ errors.code }}</view>
      </view>
      <button class="btn btn-primary btn-block" :loading="submitting" :disabled="submitting" @click="doLogin">
        {{ submitting ? '登录中…' : '登 å½•' }}
      </button>
      <view class="links">
        <text class="link" @click="go('/pages/register/register')">注册账号</text>
        <text class="link" @click="go('/pages/forgot/forgot')">忘记密码?</text>
      </view>
      <view class="tip">首次使用请扫描班主任发的班级二维码注册</view>
    </view>
  </view>
</template>
<script>
import { getCaptcha, accountLogin } from '@/api/auth.js'
import { setToken } from '@/utils/request.js'
import { getTitles, DEFAULT_TITLES } from '@/utils/site.js'
export default {
  data() {
    return {
      submitting: false,
      form: { studentNo: '', name: '', password: '', code: '', uuid: '' },
      errors: {},
      captchaEnabled: true,
      captchaImg: '',
      titles: DEFAULT_TITLES,
    }
  },
  onLoad() {
    this.loadCaptcha()
    this.loadTitles()
  },
  methods: {
    async loadTitles() {
      this.titles = await getTitles()
    },
    async loadCaptcha() {
      try {
        const res = await getCaptcha()
        this.captchaEnabled = res.captchaEnabled !== false
        this.captchaImg = res.img ? 'data:image/jpg;base64,' + res.img : ''
        this.form.uuid = res.uuid || ''
        this.form.code = ''
      } catch (e) { /* request.js å·²å¼¹ toast */ }
    },
    clearErr(k) { if (this.errors[k]) delete this.errors[k] },
    validate() {
      const errs = {}
      if (!this.form.studentNo.trim()) errs.studentNo = '请输入学号'
      if (!this.form.name.trim()) errs.name = '请输入姓名'
      if (!this.form.password) errs.password = '请输入密码'
      if (this.captchaEnabled && !this.form.code.trim()) errs.code = '请输入验证码'
      this.errors = errs
      return !Object.keys(errs).length
    },
    async doLogin() {
      if (!this.validate()) return
      this.submitting = true
      try {
        const res = await accountLogin({
          studentNo: this.form.studentNo.trim(),
          name: this.form.name.trim(),
          password: this.form.password,
          code: this.form.code.trim(),
          uuid: this.form.uuid,
        })
        setToken(res.data.token)
        if (res.data.mustChange) {
          uni.showToast({ title: '管理员已重置你的密码,请修改', icon: 'none', duration: 2000 })
          setTimeout(() => uni.redirectTo({ url: '/pages/password/change' }), 800)
        } else {
          uni.showToast({ title: '登录成功', icon: 'success' })
          setTimeout(() => uni.reLaunch({ url: '/pages/index/index' }), 500)
        }
      } catch (e) {
        if (this.captchaEnabled) this.loadCaptcha() // éªŒè¯ç ä¸€æ¬¡æ€§ï¼Œå¤±è´¥åŽåˆ·æ–°
      } finally {
        this.submitting = false
      }
    },
    go(url) { uni.navigateTo({ url }) },
  },
}
</script>
<style scoped>
button { margin: 0; padding: 0; }
button::after { border: none; }
.page { min-height: 100vh; background: #EEF2F8; padding: 0 0 60rpx; box-sizing: border-box; }
.brand {
  position: relative;
  padding: 48rpx 44rpx 96rpx;
  overflow: hidden;
  background:
    radial-gradient(420rpx 260rpx at 88% -20%, rgba(120, 165, 225, 0.38), transparent 60%),
    linear-gradient(135deg, #16345e 0%, #1F4788 55%, #2a5aa8 100%);
  border-radius: 0 0 30rpx 30rpx;
}
.brand-watermark { position: absolute; right: -36rpx; bottom: -60rpx; width: 280rpx; height: 280rpx; opacity: 0.12; }
.brand-logo { width: 380rpx; height: 84rpx; display: block; }
.brand-title { position: relative; margin-top: 26rpx; font-size: 40rpx; font-weight: 700; color: #fff; letter-spacing: 10rpx; }
.brand-sub { position: relative; margin-top: 10rpx; font-size: 24rpx; color: rgba(255, 255, 255, 0.72); letter-spacing: 2rpx; }
.card { position: relative; z-index: 1; background: #fff; margin: -56rpx 24rpx 0; border-radius: 16rpx; padding: 40rpx 30rpx 44rpx; box-shadow: 0 12rpx 36rpx rgba(31, 71, 136, 0.12); }
.field { margin-bottom: 28rpx; }
.label { display: block; font-size: 27rpx; color: #303133; margin-bottom: 12rpx; }
.field-err .label { color: #C03; }
.input { height: 88rpx; line-height: 88rpx; background: #fff; border: 1rpx solid #DCDFE6; border-radius: 8rpx; padding: 0 22rpx; font-size: 29rpx; color: #1F2D3D; }
.input.err, .field-err .input { border-color: #E5484D; background: #FDF3F3; }
.err-text { margin-top: 8rpx; color: #E5484D; font-size: 24rpx; }
.ph { color: #C0C4CC; }
.captcha-row { display: flex; align-items: center; }
.captcha-input { flex: 1; }
.captcha-img { width: 200rpx; height: 88rpx; margin-left: 20rpx; border: 1rpx solid #DCDFE6; border-radius: 8rpx; background: #F0F2F6; }
.btn { height: 88rpx; line-height: 88rpx; border-radius: 12rpx; font-size: 30rpx; letter-spacing: 6rpx; text-align: center; box-sizing: border-box; }
.btn-primary { background: linear-gradient(90deg, #16345e, #1F4788 55%, #2a5aa8); color: #fff; box-shadow: 0 8rpx 20rpx rgba(31, 71, 136, 0.28); }
.btn-block { width: 100%; }
.btn[disabled] { opacity: .6; }
.btn-primary[disabled] { color: #fff; }
.links { display: flex; justify-content: space-between; margin-top: 26rpx; }
.link { color: #1F4788; font-size: 26rpx; }
.tip { margin-top: 20rpx; text-align: center; font-size: 23rpx; color: #B4BAC6; }
</style>
src/pages/password/change.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,108 @@
<template>
  <view class="page">
    <view class="brand">
      <image class="brand-watermark" src="/static/logo-emblem-white.png" mode="aspectFit" />
      <image class="brand-logo" src="/static/logo-head-white.png" mode="aspectFit" />
      <view class="brand-title">修改密码</view>
      <view class="brand-sub">修改成功后,其他设备上的登录会被退出</view>
    </view>
    <view class="card">
      <view class="field" :class="{ 'field-err': errors.old }">
        <text class="label">原密码</text>
        <input class="input" v-model="form.old" type="password" placeholder="请输入当前密码" placeholder-class="ph" @input="clearErr('old')" />
        <view v-if="errors.old" class="err-text">{{ errors.old }}</view>
      </view>
      <view class="field" :class="{ 'field-err': errors.password }">
        <text class="label">新密码</text>
        <input class="input" v-model="form.password" type="password" placeholder="8-20位,须含字母和数字" placeholder-class="ph" @input="clearErr('password')" />
        <view v-if="errors.password" class="err-text">{{ errors.password }}</view>
      </view>
      <view class="field" :class="{ 'field-err': errors.confirm }">
        <text class="label">确认新密码</text>
        <input class="input" v-model="form.confirm" type="password" placeholder="请再次输入新密码" placeholder-class="ph" @input="clearErr('confirm')" />
        <view v-if="errors.confirm" class="err-text">{{ errors.confirm }}</view>
      </view>
      <button class="btn btn-primary btn-block" :loading="submitting" :disabled="submitting" @click="doChange">
        {{ submitting ? '提交中…' : '确认修改' }}
      </button>
      <view class="tip">忘记原密码?可退出后在登录页用“忘记密码”自助重置</view>
    </view>
  </view>
</template>
<script>
import { accountChange } from '@/api/auth.js'
import { setToken } from '@/utils/request.js'
export default {
  data() {
    return { submitting: false, form: { old: '', password: '', confirm: '' }, errors: {} }
  },
  methods: {
    clearErr(k) { if (this.errors[k]) delete this.errors[k] },
    validate() {
      const errs = {}
      if (!this.form.old) errs.old = '请输入原密码'
      const p = this.form.password
      if (!p) errs.password = '请输入新密码'
      else if (!/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d!@#$%^&*_.\-+=?]{8,20}$/.test(p)) errs.password = '8-20位,须同时包含字母和数字'
      else if (p === this.form.old) errs.password = '新密码不能与原密码相同'
      if (this.form.confirm !== p) errs.confirm = '两次输入的密码不一致'
      this.errors = errs
      return !Object.keys(errs).length
    },
    async doChange() {
      if (!this.validate()) return
      this.submitting = true
      try {
        const res = await accountChange({ oldPassword: this.form.old, newPassword: this.form.password })
        if (res.data && res.data.token) setToken(res.data.token) // å½“前设备保持登录(换发新 token)
        uni.showToast({ title: '密码修改成功', icon: 'success' })
        setTimeout(() => uni.reLaunch({ url: '/pages/index/index' }), 700)
      } catch (e) { /* request.js å·²å¼¹ toast */ }
      this.submitting = false
    },
  },
}
</script>
<style scoped>
button { margin: 0; padding: 0; }
button::after { border: none; }
.page { min-height: 100vh; background: #EEF2F8; padding: 0 0 60rpx; box-sizing: border-box; }
.brand {
  position: relative;
  padding: 48rpx 44rpx 96rpx;
  overflow: hidden;
  background:
    radial-gradient(420rpx 260rpx at 88% -20%, rgba(120, 165, 225, 0.38), transparent 60%),
    linear-gradient(135deg, #16345e 0%, #1F4788 55%, #2a5aa8 100%);
  border-radius: 0 0 30rpx 30rpx;
}
.brand-watermark { position: absolute; right: -36rpx; bottom: -60rpx; width: 280rpx; height: 280rpx; opacity: 0.12; }
.brand-logo { width: 380rpx; height: 84rpx; display: block; }
.brand-title { position: relative; margin-top: 26rpx; font-size: 40rpx; font-weight: 700; color: #fff; letter-spacing: 8rpx; }
.brand-sub { position: relative; margin-top: 10rpx; font-size: 24rpx; color: rgba(255, 255, 255, 0.72); line-height: 1.5; }
.card { position: relative; z-index: 1; background: #fff; margin: -56rpx 24rpx 0; border-radius: 16rpx; padding: 40rpx 30rpx 44rpx; box-shadow: 0 12rpx 36rpx rgba(31, 71, 136, 0.12); }
.field { margin-bottom: 28rpx; }
.label { display: block; font-size: 27rpx; color: #303133; margin-bottom: 12rpx; }
.field-err .label { color: #C03; }
.input { height: 88rpx; line-height: 88rpx; background: #fff; border: 1rpx solid #DCDFE6; border-radius: 8rpx; padding: 0 22rpx; font-size: 29rpx; color: #1F2D3D; }
.input.err, .field-err .input { border-color: #E5484D; background: #FDF3F3; }
.err-text { margin-top: 8rpx; color: #E5484D; font-size: 24rpx; }
.ph { color: #C0C4CC; }
.btn { height: 88rpx; line-height: 88rpx; border-radius: 12rpx; font-size: 30rpx; letter-spacing: 4rpx; text-align: center; box-sizing: border-box; }
.btn-primary { background: linear-gradient(90deg, #16345e, #1F4788 55%, #2a5aa8); color: #fff; box-shadow: 0 8rpx 20rpx rgba(31, 71, 136, 0.28); }
.btn-block { width: 100%; }
.btn[disabled] { opacity: .6; }
.btn-primary[disabled] { color: #fff; }
.tip { margin-top: 26rpx; text-align: center; font-size: 23rpx; color: #B4BAC6; }
</style>
src/pages/plan/form.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,597 @@
<template>
  <view class="form-page">
    <view v-if="loading" class="state">加载中…</view>
    <!-- æœªç»‘定/不在填报范围:不展示表单 -->
    <view v-else-if="errorMsg" class="err-state">
      <view class="err-icon">!</view>
      <view class="err-title">暂时无法填报</view>
      <view class="err-msg">{{ errorMsg }}</view>
      <button class="btn btn-primary err-btn" @click="goHome">去完成身份绑定 / è¿”回首页</button>
    </view>
    <block v-else>
      <!-- ä»»åŠ¡ä¿¡æ¯æ¡ -->
      <view class="task-head">
        <view class="th-top">
          <text class="th-title">{{ meta.taskName || '信息填报' }}</text>
          <text class="th-tag" :class="meta.readonly ? 'ok' : (meta.recordStatus === '0' ? 'draft' : 'todo')">{{ statusText() }}</text>
        </view>
        <view class="th-meta">{{ meta.termText }}</view>
        <view class="th-meta">填报时间:{{ meta.fillStartDate }} ~ {{ meta.fillEndDate }}</view>
        <view v-if="meta.readonly" class="th-note">已正式提交,内容只读;如需修改请联系班级管理人退回。</view>
      </view>
      <!-- æ ¡éªŒé”™è¯¯æ±‡æ€» -->
      <view v-if="Object.keys(errors).length && !meta.readonly" class="err-banner">
        è¿˜æœ‰ {{ Object.keys(errors).length }} é¡¹å¡«å†™æœ‰è¯¯ï¼Œè¯·æŒ‰çº¢è‰²æç¤ºä¿®æ”¹åŽæäº¤
      </view>
      <!-- åˆ†ç»„表单 -->
      <view class="group" v-for="(g, gi) in groups" :key="gi">
        <view class="group-title">{{ groupNo(gi) }} {{ g.groupName }}</view>
        <view class="field" v-for="f in g.fields" :key="f.code" :class="{ 'field-err': errors[f.code] }">
          <view class="f-label"><text v-if="needReq(f)" class="req">*</text>{{ f.label }}</view>
          <block v-if="isReadonly(f)">
            <view class="f-ro" v-if="form[f.code] !== undefined && form[f.code] !== ''">{{ form[f.code] }}</view>
            <view class="f-ro faint" v-else>{{ autoHint(f) }}</view>
          </block>
          <block v-else>
            <!-- ä¸‹æ‹‰ -->
            <picker v-if="f.type === 'select' && optLabels(f).length" :range="optLabels(f)" :value="curIndex(f)" @change="e => onSelect(f, e)">
              <view class="f-ctrl" :class="{ err: errors[f.code] }">
                <text :class="form[f.code] ? 'on' : 'off'">{{ curLabel(f) }}</text>
                <text class="caret">▾</text>
              </view>
            </picker>
            <!-- å•选 -->
            <view v-else-if="f.type === 'radio' && optLabels(f).length" class="f-radios" :class="{ err: errors[f.code] }">
              <view v-for="o in f.options" :key="o.value" class="f-radio" :class="{ on: String(form[f.code]) === String(o.value) }" @click="pickRadio(f, o)">{{ o.label }}</view>
            </view>
            <!-- æ—¥æœŸ -->
            <picker v-else-if="f.type === 'date'" mode="date" :value="form[f.code] || ''" @change="e => { form[f.code] = e.detail.value; clearErr(f.code) }">
              <view class="f-ctrl" :class="{ err: errors[f.code] }">
                <text :class="form[f.code] ? 'on' : 'off'">{{ form[f.code] || '请选择日期' }}</text>
                <text class="caret">▾</text>
              </view>
            </picker>
            <!-- çœä»½ -->
            <picker v-else-if="f.type === 'province'" :range="provinceNames" :value="provinceIndex(f)" @change="e => onProvinceChange(f, e)">
              <view class="f-ctrl" :class="{ err: errors[f.code] }">
                <text :class="form[f.code] ? 'on' : 'off'">{{ form[f.code] || '请选择省份' }}</text>
                <text class="caret">▾</text>
              </view>
            </picker>
            <!-- åŸŽå¸‚:随省份二级联动,未选省份前不可点 -->
            <picker v-else-if="f.type === 'city'" :range="cityList(f)" :value="cityIndex(f)"
                    :disabled="!cityList(f).length" @change="e => onCityChange(f, e)">
              <view class="f-ctrl" :class="{ err: errors[f.code], off: !cityList(f).length }">
                <text :class="form[f.code] ? 'on' : 'off'">{{ form[f.code] || (cityList(f).length ? '请选择城市' : '请先选择省份') }}</text>
                <text class="caret">▾</text>
              </view>
            </picker>
            <!-- åœ°åŒºï¼šä¸€ä¸ªå­—段里连着选省和市,合并存为「省/市」 -->
            <view v-else-if="f.type === 'region'" class="f-region">
              <picker class="f-region-p" :range="provinceNames" :value="regionProvinceIndex(f)" @change="e => onRegionProvince(f, e)">
                <view class="f-ctrl" :class="{ err: errors[f.code] }">
                  <text :class="regionProvince(f) ? 'on' : 'off'">{{ regionProvince(f) || '请选择省份' }}</text>
                  <text class="caret">▾</text>
                </view>
              </picker>
              <picker class="f-region-p" :range="regionCityList(f)" :value="regionCityIndex(f)" :disabled="!regionCityList(f).length"
                      @change="e => onRegionCity(f, e)">
                <view class="f-ctrl" :class="{ err: errors[f.code], off: !regionCityList(f).length }">
                  <text :class="regionCity(f) ? 'on' : 'off'">{{ regionCity(f) || (regionCityList(f).length ? '请选择城市' : '请先选择省份') }}</text>
                  <text class="caret">▾</text>
                </view>
              </picker>
            </view>
            <!-- æ–‡ä»¶ä¸Šä¼ ï¼ˆå›¾ç‰‡/PDF/Office ææ–™ç»Ÿä¸€å…¥å£ï¼‰ -->
            <view v-else-if="f.type === 'file'" class="f-files">
              <view class="f-up-grid" v-if="imgList(f).length">
                <view class="f-up-cell" v-for="(p, i) in imgList(f)" :key="'i' + i">
                  <image class="f-up-img" :src="fullUrl(p)" mode="aspectFill" @click="previewImg(f, i)" />
                  <view v-if="!meta.readonly" class="f-up-del" @click.stop="removeFileByPath(f, p)">×</view>
                </view>
              </view>
              <view class="f-file-row" v-for="(p, i) in docList(f)" :key="'d' + i">
                <text class="f-file-name" @click="openFile(p)">{{ fileNameOf(p) }}</text>
                <text v-if="!meta.readonly" class="f-file-del" @click="removeFileByPath(f, p)">删除</text>
              </view>
              <view v-if="!meta.readonly && fileList(f).length < maxCount(f)" class="f-file-add" :class="{ err: errors[f.code] }" @click="chooseFiles(f)">
                ï¼‹ ä¸Šä¼ æ–‡ä»¶ï¼ˆ{{ fileList(f).length }}/{{ maxCount(f) }},单个≤{{ MAX_UPLOAD_MB }}M)
              </view>
            </view>
            <!-- å¤šè¡Œ -->
            <textarea v-else-if="f.type === 'textarea'" v-model="form[f.code]" :placeholder="f.placeholder || '请输入'" :maxlength="f.maxLen || 500" class="f-area" :class="{ err: errors[f.code] }" auto-height @input="clearErr(f.code)" />
            <!-- æ–‡æœ¬/数字/电话/信用代码 -->
            <input v-else class="f-input" :class="{ err: errors[f.code] }" :type="f.type === 'number' ? 'number' : 'text'"
                   v-model="form[f.code]" :placeholder="f.placeholder || '请输入'" :maxlength="f.maxLen || 200"
                   @input="e => onInput(e, f)" />
          </block>
          <view v-if="errors[f.code]" class="err-text">{{ errors[f.code] }}</view>
          <view v-else-if="f.help" class="f-help">{{ f.help }}</view>
        </view>
      </view>
      <!-- åº•部操作 -->
      <view v-if="!meta.readonly" class="bottom-bar">
        <button class="btn btn-draft" @click="doSave('draft')">暂存草稿</button>
        <button class="btn btn-submit" :loading="submitting" @click="doSave('submit')">正式提交</button>
      </view>
    </block>
  </view>
</template>
<script>
import { getTaskForm, saveTaskDraft, submitTask } from '@/api/task.js'
import { PROVINCES, citiesOf } from '@/utils/region.js'
import { uploadFile } from '@/utils/request.js'
import config from '@/config.js'
export default {
  data() {
    // å•个上传文件大小上限(MB),与服务端 spring.servlet.multipart.max-file-size=10MB ä¿æŒä¸€è‡´
    return { MAX_UPLOAD_MB: 10, taskId: null, loading: true, submitting: false, meta: {}, groups: [], form: {}, errors: {}, errorMsg: '', provinceNames: PROVINCES }
  },
  onLoad(options) {
    this.taskId = options.taskId
    this.load()
  },
  methods: {
    async load() {
      this.loading = true
      this.errorMsg = ''
      try {
        const res = await getTaskForm(this.taskId)
        const d = res.data
        this.meta = d
        this.groups = this.normalizeGroups((d.schema && d.schema.groups) || [])
        this.form = d.form || {}
        if (!d.open && !d.readonly && !this.meta.recordStatus) {
          this.errorMsg = '该填报任务当前不在开放期内,或你的身份尚未完成绑定/班级登记。'
        }
      } catch (e) {
        this.errorMsg = (e && e.msg) || '无法打开该填报任务,请先完成身份绑定/班级登记。'
      }
      this.loading = false
    },
    goHome() {
      uni.reLaunch({ url: '/pages/index/index' })
    },
    statusText() {
      if (this.meta.readonly) return '已提交'
      if (this.meta.recordStatus === '0') return '草稿'
      return this.meta.open ? '待填写' : '已截止'
    },
    groupNo(gi) {
      const map = ['一', '二', '三', '四', '五', '六']
      return map[gi] || (gi + 1)
    },
    needReq(f) { return f.required === true },
    isReadonly(f) { return f.readonly === true || !!f.auto },
    autoHint(f) {
      if (f.auto === 'roster') return '(学生档案自动带出)'
      if (f.auto === 'task') return '(任务自动带出)'
      if (f.auto === 'server') return '(由系统判定)'
      return '(只读)'
    },
    optList(f) { return Array.isArray(f.options) ? f.options : [] },
    optLabels(f) { return this.optList(f).map(o => o.label) },
    curIndex(f) {
      const idx = this.optList(f).findIndex(o => String(o.value) === String(this.form[f.code]))
      return idx < 0 ? 0 : idx
    },
    curLabel(f) {
      const idx = this.curIndex(f)
      const opts = this.optList(f)
      return this.form[f.code] && opts[idx] ? opts[idx].label : '请选择'
    },
    onSelect(f, e) {
      const o = this.optList(f)[Number(e.detail.value)]
      this.form[f.code] = o ? o.value : ''
      // è¯¥ä¸‹æ‹‰è‹¥æ­£è¢«åŸŽå¸‚当作省份联动源,换值后同样清掉跟随的城市
      this.allFields().forEach(x => {
        if (x.type === 'city' && this.linkCodeOf(x) === f.code) this.form[x.code] = ''
      })
      this.clearErr(f.code)
    },
    pickRadio(f, o) { this.form[f.code] = o.value; this.clearErr(f.code) },
    // ---- çœä»½ / åŸŽå¸‚(二级联动)----
    /**
     * å…¼å®¹æ—©æœŸ schema å¿«ç…§ï¼šçœå¸‚字段曾统一标为已废弃的 region ç±»åž‹ã€‚
     * ä»»åŠ¡ schema æ˜¯å‘布时落库的快照,改动字段类型不会回溯旧任务,故在此还原。
     */
    normalizeGroups(groups) {
      const all = []
      for (const g of groups) for (const f of (g.fields || [])) {
        // ä»…内置字段(编码固定为 province / city)才从 region æ‹†å¼€ï¼›
        // ç”¨æˆ·æ–°å¢žçš„「地区」字段本身就是 region,必须原样保留
        if (f.type === 'region' && (f.code === 'province' || f.code === 'city')) {
          f.type = f.code === 'city' ? 'city' : 'province'
        }
        // ã€Œå›¾ç‰‡ä¸Šä¼ ã€å·²å¹¶å…¥ã€Œæ–‡ä»¶ä¸Šä¼ ã€ï¼šè€ä»»åŠ¡ schema å¿«ç…§æŒ‰æ­¤è¿ç§»ï¼Œä¿ç•™åŽŸ 6 å¼ é»˜è®¤ä¸Šé™
        if (f.type === 'image') {
          if (!f.maxCount) f.maxCount = 6
          f.type = 'file'
        }
        // åŽ†å²ç‰ˆæœ¬æŠŠã€ŒåŸŽå¸‚ã€å­˜æˆå¸¦è¡Œæ”¿åŒºåˆ’æ ‡è®°çš„æ™®é€šä¸‹æ‹‰ï¼ˆé€‰é¡¹æ˜¯å…¨é‡åŸŽå¸‚åˆ—è¡¨ï¼‰ã€‚
        // å‡çº§ä¸º city ç±»åž‹èµ°çœå¸‚联动渲染,忽略其快照里的静态选项。
        if (f.type === 'select' && f.optionSource === 'region' && (f.code === 'city' || f.linkTo)) {
          f.type = 'city'
        }
        all.push(f)
      }
      const first = all.find(f => this.isProvinceSource(f))
      all.forEach(f => { if (f.type === 'city' && !f.linkTo && first) f.linkTo = first.code })
      return groups
    },
    /**
     * å­—段能否作为城市的省份联动源:内置「省份」类型,
     * æˆ–选项里存有可识别省份名的「下拉/单选」字段(管理端手动配省份下拉的场景)。
     */
    isProvinceSource(f) {
      if (f.type === 'province') return true
      if (f.type === 'select' || f.type === 'radio') {
        return this.optList(f).some(o => citiesOf(String(o.value || o.label || '')).length > 0)
      }
      return false
    },
    allFields() {
      const out = []
      for (const g of this.groups) for (const f of (g.fields || [])) out.push(f)
      return out
    },
    /** åŸŽå¸‚字段联动的省份字段 code:优先取配置的 linkTo,否则退回表单里第一个省份源字段 */
    linkCodeOf(f) {
      const all = this.allFields()
      if (f.linkTo && all.some(x => this.isProvinceSource(x) && x.code === f.linkTo)) return f.linkTo
      const first = all.find(x => this.isProvinceSource(x))
      return first ? first.code : ''
    },
    /** å½“前省份下可选的地市;省份未选时为空数组,picker éšä¹‹ç¦ç”¨ */
    cityList(f) {
      return citiesOf(this.form[this.linkCodeOf(f)])
    },
    provinceIndex(f) {
      const i = PROVINCES.indexOf(this.form[f.code])
      return i < 0 ? 0 : i
    },
    cityIndex(f) {
      const i = this.cityList(f).indexOf(this.form[f.code])
      return i < 0 ? 0 : i
    },
    onProvinceChange(f, e) {
      this.form[f.code] = PROVINCES[Number(e.detail.value)] || ''
      // æ¢çœåŽæ¸…空跟随它的城市,避免留下「江苏 + æ·±åœ³ã€è¿™ç±»çŸ›ç›¾ç»„合
      this.allFields().forEach(x => {
        if (x.type === 'city' && this.linkCodeOf(x) === f.code) this.form[x.code] = ''
      })
      this.clearErr(f.code)
    },
    onCityChange(f, e) {
      const list = this.cityList(f)
      this.form[f.code] = list[Number(e.detail.value)] || ''
      this.clearErr(f.code)
    },
    // ---- åœ°åŒºï¼ˆçœ+市合并成一个字段,存「省/市」)----
    /** æ‹†å‡ºå·²å­˜çš„省市;无值或格式异常时返回空,不抛错 */
    regionParts(f) {
      const v = this.form[f.code] == null ? '' : String(this.form[f.code])
      const i = v.indexOf('/')
      return i < 0 ? { p: v, c: '' } : { p: v.slice(0, i), c: v.slice(i + 1) }
    },
    regionProvince(f) { return this.regionParts(f).p },
    regionCity(f) { return this.regionParts(f).c },
    regionCityList(f) { return citiesOf(this.regionProvince(f)) },
    regionProvinceIndex(f) {
      const i = PROVINCES.indexOf(this.regionProvince(f))
      return i < 0 ? 0 : i
    },
    regionCityIndex(f) {
      const i = this.regionCityList(f).indexOf(this.regionCity(f))
      return i < 0 ? 0 : i
    },
    onRegionProvince(f, e) {
      // æ¢çœå³æ¸…空已选市,避免留下「江苏省/深圳市」这类矛盾值
      this.form[f.code] = PROVINCES[Number(e.detail.value)] || ''
      this.clearErr(f.code)
    },
    onRegionCity(f, e) {
      const p = this.regionProvince(f)
      const c = this.regionCityList(f)[Number(e.detail.value)] || ''
      this.form[f.code] = c ? (p + '/' + c) : p
      this.clearErr(f.code)
    },
    onInput(e, f) {
      let val = e.detail.value
      if (f.type === 'creditCode') val = val.toUpperCase()
      this.form[f.code] = val
      this.clearErr(f.code)
    },
    // ---- å›¾ç‰‡ / æ–‡ä»¶ä¸Šä¼  ----
    /** å–字段的已上传路径列表;兼容「数组」与历史「逗号拼接字符串」两种存储 */
    fileList(f) {
      const v = this.form[f.code]
      if (Array.isArray(v)) return v.filter(Boolean)
      if (typeof v === 'string' && v.trim()) return v.split(',').map(s => s.trim()).filter(Boolean)
      return []
    },
    maxCount(f) {
      const n = Number(f.maxCount)
      if (n > 0) return Math.min(n, 9)
      return 3
    },
    /** æ˜¯å¦å›¾ç‰‡æ–‡ä»¶ï¼ˆæŒ‰æ‰©å±•名判断,用于缩略图预览) */
    isImg(p) { return /\.(bmp|gif|jpe?g|png)$/i.test(String(p || '')) },
    imgList(f) { return this.fileList(f).filter(p => this.isImg(p)) },
    docList(f) { return this.fileList(f).filter(p => !this.isImg(p)) },
    /** ç›¸å¯¹è·¯å¾„ â†’ å¯è®¿é—® URL(/profile/** å·²æ”¾è¡Œï¼Œèµ°åŒä¸€åŸŸåå‰ç¼€ï¼‰ */
    fullUrl(p) {
      if (!p) return ''
      if (/^https?:\/\//.test(p)) return p
      return config.baseUrl + p
    },
    fileNameOf(p) {
      const s = String(p || '')
      return s.slice(s.lastIndexOf('/') + 1)
    },
    /** è¶…出 10MB çš„æ–‡ä»¶å…ˆè¡Œæ‹¦æˆªï¼Œç»™å‡ºæ˜Žç¡®æç¤º */
    filterOversize(items, sizeOf) {
      const keep = []
      let skipped = 0
      for (const it of items) {
        if (sizeOf(it) > this.MAX_UPLOAD_MB * 1024 * 1024) skipped++
        else keep.push(it)
      }
      if (skipped) uni.showToast({ title: '文件不得大于' + this.MAX_UPLOAD_MB + 'M,已跳过 ' + skipped + ' ä¸ªè¶…大文件', icon: 'none', duration: 2600 })
      return keep
    },
    chooseImages(f) {
      const left = this.maxCount(f) - this.fileList(f).length
      if (left <= 0) { uni.showToast({ title: '最多上传 ' + this.maxCount(f) + ' ä¸ªæ–‡ä»¶', icon: 'none' }); return }
      uni.chooseImage({
        count: Math.min(left, 9),
        sizeType: ['compressed'],
        success: (res) => {
          const paths = res.tempFilePaths || []
          const metas = res.tempFiles || []
          // éƒ¨åˆ†å¹³å° tempFiles å¸¦ size,可前端预判;拿不到时由服务端 10MB ä¸Šé™å…œåº•
          if (metas.length && metas.every(m => typeof m.size === 'number')) {
            const zipped = paths.map((p, i) => ({ p, size: (metas[i] || {}).size || 0 }))
            this.uploadPaths(f, this.filterOversize(zipped, x => x.size).map(x => x.p))
          } else {
            this.uploadPaths(f, paths)
          }
        }
      })
    },
    chooseFiles(f) {
      const left = this.maxCount(f) - this.fileList(f).length
      if (left <= 0) { uni.showToast({ title: '最多上传 ' + this.maxCount(f) + ' ä¸ªæ–‡ä»¶', icon: 'none' }); return }
      // #ifdef H5
      const input = document.createElement('input')
      input.type = 'file'
      input.multiple = true
      input.accept = '.bmp,.gif,.jpg,.jpeg,.png,.pdf,.doc,.docx,.xls,.xlsx,.txt'
      input.onchange = () => {
        const all = Array.from(input.files || [])
        const files = this.filterOversize(all, x => x.size).slice(0, left)
        this.uploadFiles(f, files)
      }
      input.click()
      // #endif
      // #ifndef H5
      // å°ç¨‹åºç«¯æš‚以选图方式上传(uni.uploadFile å¯¹æœ¬åœ°ä¸´æ—¶è·¯å¾„通用)
      this.chooseImages(f)
      // #endif
    },
    /** H5:直接上传 File å¯¹è±¡ */
    uploadFiles(f, files) {
      this.doUpload(f, files.map(file => ({ file })))
    },
    /** å°ç¨‹åº/H5:按临时路径逐个上传 */
    uploadPaths(f, paths) {
      this.doUpload(f, paths.map(p => ({ filePath: p })))
    },
    async doUpload(f, jobs) {
      if (!jobs.length) return
      uni.showLoading({ title: '上传中…', mask: true })
      const names = this.fileList(f).slice()
      try {
        for (const job of jobs) {
          if (names.length >= this.maxCount(f)) break
          const res = await uploadFile(job)
          if (res && res.fileName) names.push(res.fileName)
          else uni.showToast({ title: '上传响应异常:未返回文件地址', icon: 'none' })
        }
        this.form[f.code] = names
        this.clearErr(f.code)
      } catch (e) { /* uploadFile å·²å¼¹é”™ */ }
      uni.hideLoading()
    },
    removeFile(f, i) {
      const names = this.fileList(f).slice()
      names.splice(i, 1)
      this.form[f.code] = names
    },
    removeFileByPath(f, p) {
      const i = this.fileList(f).indexOf(p)
      if (i >= 0) this.removeFile(f, i)
    },
    previewImg(f, i) {
      const urls = this.imgList(f).map(p => this.fullUrl(p))
      if (urls.length) uni.previewImage({ urls, current: i })
    },
    openFile(p) {
      const url = this.fullUrl(p)
      // #ifdef H5
      window.open(url)
      // #endif
      // #ifndef H5
      uni.downloadFile({
        url,
        success: (res) => uni.openDocument({
          filePath: res.tempFilePath,
          fail: () => uni.showToast({ title: '暂不支持预览该文件类型', icon: 'none' })
        })
      })
      // #endif
    },
    clearErr(code) {
      if (this.errors[code]) {
        const o = {}
        Object.keys(this.errors).forEach(k => { if (k !== code) o[k] = this.errors[k] })
        this.errors = o
      }
    },
    doSave(mode) {
      if (mode === 'submit') {
        const errs = this.validate()
        this.errors = errs
        const keys = Object.keys(errs)
        if (keys.length) {
          // åªå¼¹ç¬¬ä¸€æ¡ï¼Œä½†å¸¦ä¸Šæ¡æ•°ï¼Œé¿å…ç”¨æˆ·ä»¥ä¸ºåªæœ‰è¿™ä¸€å¤„é”™
          const title = errs[keys[0]] + (keys.length > 1 ? `(共 ${keys.length} é¡¹å¾…修改)` : '')
          uni.showToast({ title, icon: 'none', duration: 2600 })
          return
        }
      }
      this.submitting = true
      const api = mode === 'submit' ? submitTask : saveTaskDraft
      api({ taskId: this.taskId, form: this.form })
        .then(() => {
          uni.showToast({ title: mode === 'submit' ? '提交成功' : '草稿已保存', icon: 'success' })
          setTimeout(() => uni.navigateBack(), 600)
        })
        .catch(() => {})
        .finally(() => { this.submitting = false })
    },
    validate() {
      const errs = {}
      for (const g of this.groups) {
        for (const f of g.fields || []) {
          if (this.isReadonly(f)) continue
          const code = f.code
          // å›¾ç‰‡/文件字段:按列表判必填,不走文本/数字类校验
          if (f.type === 'image' || f.type === 'file') {
            if (f.required === true && this.fileList(f).length === 0) errs[code] = '请上传「' + f.label + '」'
            continue
          }
          const v = (this.form[code] === undefined || this.form[code] === null) ? '' : String(this.form[code]).trim()
          if (f.required === true && !v) { errs[code] = '请填写「' + f.label + '」'; continue }
          if (!v) continue
          if (f.type === 'province' && PROVINCES.indexOf(v) < 0) { errs[code] = '请选择有效的「' + f.label + '」'; continue }
          if (f.type === 'city') {
            if (!this.linkCodeOf(f)) { errs[code] = '请先选择省份,再选「' + f.label + '」'; continue }
            const cities = this.cityList(f)
            if (cities.length && cities.indexOf(v) < 0) { errs[code] = '「' + f.label + '」与所选省份不符,请重新选择'; continue }
          }
          if (f.type === 'region') {
            const p = this.regionProvince(f), c = this.regionCity(f)
            if (!p || !c) { errs[code] = '请选择完整的「' + f.label + '」(省和市)'; continue }
            if (citiesOf(p).indexOf(c) < 0) { errs[code] = '「' + f.label + '」所选城市不属于该省份,请重新选择'; continue }
          }
          if (f.type === 'phone' && !/^1[3-9]\d{9}$/.test(v)) { errs[code] = '「' + f.label + '」请填写 11 ä½å¤§é™†æ‰‹æœºå·'; continue }
          if (f.type === 'creditCode' && !/^[0-9A-HJ-NPQRTUWXY]{18}$/.test(v)) { errs[code] = '「' + f.label + '」须为 18 ä½ç»Ÿä¸€ç¤¾ä¼šä¿¡ç”¨ä»£ç '; continue }
          if (f.type === 'number') {
            const n = Number(v)
            if (Number.isNaN(n)) { errs[code] = '「' + f.label + '」请输入数字'; continue }
            if (f.min !== undefined && f.min !== null && n < Number(f.min)) { errs[code] = '「' + f.label + '」不能小于 ' + f.min; continue }
            if (f.max !== undefined && f.max !== null && n > Number(f.max)) { errs[code] = '「' + f.label + '」不能大于 ' + f.max; continue }
          }
          if (f.minLen && v.length < Number(f.minLen)) { errs[code] = '「' + f.label + '」至少 ' + f.minLen + ' ä¸ªå­—'; continue }
          if (f.maxLen && v.length > Number(f.maxLen)) { errs[code] = '「' + f.label + '」最多 ' + f.maxLen + ' ä¸ªå­—'; continue }
        }
      }
      return errs
    },
  },
}
</script>
<style scoped>
button { margin: 0; padding: 0; }
button::after { border: none; }
.form-page { background: #EEF2F8; min-height: 100vh; padding: 24rpx 24rpx 200rpx; box-sizing: border-box; }
.state { padding-top: 200rpx; text-align: center; color: #8A94A6; }
/* æ— æ³•填报提示 */
.err-state { padding: 160rpx 60rpx 0; display: flex; flex-direction: column; align-items: center; text-align: center; }
.err-icon { width: 96rpx; height: 96rpx; line-height: 96rpx; border-radius: 50%; background: #FBF0EE; color: #E5484D; font-size: 52rpx; font-weight: 700; text-align: center; }
.err-title { margin-top: 26rpx; font-size: 34rpx; font-weight: 600; color: #1F2D3D; }
.err-msg { margin-top: 16rpx; font-size: 26rpx; color: #8A94A6; line-height: 1.6; }
.err-btn { margin-top: 60rpx; width: 100%; }
.btn { height: 88rpx; line-height: 88rpx; border-radius: 12rpx; font-size: 30rpx; letter-spacing: 4rpx; text-align: center; box-sizing: border-box; }
.btn-primary { background: linear-gradient(90deg, #16345e, #1F4788 55%, #2a5aa8); color: #fff; box-shadow: 0 8rpx 20rpx rgba(31, 71, 136, 0.28); }
/* ä»»åŠ¡ä¿¡æ¯ */
.task-head { background: #fff; border: 1rpx solid #EBEDF1; border-top: 6rpx solid #1F4788; border-radius: 16rpx; padding: 26rpx 28rpx; margin-bottom: 18rpx; box-shadow: 0 4rpx 14rpx rgba(31, 71, 136, 0.05); }
.th-top { display: flex; justify-content: space-between; align-items: flex-start; }
.th-title { flex: 1; font-size: 31rpx; font-weight: 600; color: #1F2D3D; line-height: 1.4; }
.th-tag { margin-left: 16rpx; font-size: 23rpx; padding: 3rpx 14rpx; border-radius: 6rpx; flex-shrink: 0; }
.th-tag.ok { color: #1D9D5F; background: #EAF7F0; }
.th-tag.draft { color: #B36A00; background: #FBF4E2; }
.th-tag.todo { color: #1F4788; background: #E8EFF9; }
.th-meta { margin-top: 10rpx; font-size: 24rpx; color: #7C8698; }
.th-note { margin-top: 12rpx; font-size: 24rpx; color: #B36A00; }
/* é”™è¯¯æ±‡æ€» */
.err-banner { background: #FDF3F3; border: 1rpx solid #F5C6C8; color: #C03; border-radius: 8rpx; padding: 16rpx 20rpx; font-size: 25rpx; margin-bottom: 18rpx; }
/* åˆ†ç»„ */
.group { background: #fff; border: 1rpx solid #EBEDF1; border-radius: 12rpx; padding: 6rpx 28rpx 18rpx; margin-bottom: 18rpx; }
.group-title { font-size: 29rpx; font-weight: 600; color: #1F2D3D; padding: 22rpx 0 4rpx 20rpx; border-bottom: 1rpx solid #F2F3F6; margin-bottom: 4rpx; border-left: 8rpx solid #1F4788; border-top-left-radius: 4rpx; }
/* å­—段 */
.field { padding: 18rpx 0 2rpx; }
.field-err .f-label { color: #C03; }
.f-label { font-size: 26rpx; color: #303133; margin-bottom: 12rpx; }
.req { color: #E5484D; margin-right: 6rpx; font-weight: 700; }
.f-input, .f-area, .f-ctrl { background: #fff; border: 1rpx solid #DCDFE6; border-radius: 8rpx; padding: 0 20rpx; font-size: 28rpx; color: #1F2D3D; width: 100%; box-sizing: border-box; }
.f-input { height: 84rpx; line-height: 84rpx; }
.f-ctrl { height: 84rpx; line-height: 84rpx; display: flex; justify-content: space-between; align-items: center; }
.f-area { padding: 18rpx 20rpx; min-height: 120rpx; }
.f-input.err, .f-area.err, .f-ctrl.err { border-color: #E5484D; background: #FDF3F3; }
.f-radios.err { border-color: #E5484D; }
.off { color: #B4BAC6; }
.on { color: #1F2D3D; }
.caret { color: #B4BAC6; }
.f-region { display: flex; gap: 16rpx; }
.f-region-p { flex: 1; min-width: 0; }
.f-radios { display: flex; flex-wrap: wrap; gap: 18rpx; border: 1rpx solid transparent; border-radius: 8rpx; padding: 4rpx; }
.f-radio { border: 1rpx solid #DCDFE6; color: #6B7280; border-radius: 8rpx; padding: 12rpx 26rpx; font-size: 26rpx; }
.f-radio.on { border-color: #1F4788; color: #1F4788; background: #E8EFF9; font-weight: 600; }
.f-ro { font-size: 28rpx; color: #303133; padding: 16rpx 20rpx; background: #F7F8FA; border-radius: 8rpx; }
.f-ro.faint { color: #B4BAC6; }
.err-text { margin-top: 8rpx; font-size: 23rpx; color: #E5484D; }
.f-help { margin-top: 8rpx; font-size: 22rpx; color: #9AA2B1; }
/* ä¸Šä¼ åŒºï¼šå›¾ç‰‡ç¼©ç•¥å›¾ */
.f-up-grid { display: flex; flex-wrap: wrap; gap: 16rpx; }
.f-up-cell { position: relative; width: 160rpx; height: 160rpx; border-radius: 8rpx; overflow: hidden; }
.f-up-img { width: 100%; height: 100%; background: #F2F3F6; }
.f-up-del { position: absolute; top: 0; right: 0; width: 40rpx; height: 40rpx; line-height: 36rpx; text-align: center; background: rgba(0,0,0,.55); color: #fff; font-size: 28rpx; border-bottom-left-radius: 8rpx; }
/* æ–‡ä»¶ä¸Šä¼ ï¼ˆå›¾ç‰‡/PDF/Office ç»Ÿä¸€ï¼‰ */
.f-files { display: flex; flex-direction: column; gap: 12rpx; }
.f-file-row { display: flex; justify-content: space-between; align-items: center; background: #F7F8FA; border: 1rpx solid #EBEDF1; border-radius: 8rpx; padding: 16rpx 20rpx; }
.f-file-name { font-size: 26rpx; color: #1F4788; word-break: break-all; flex: 1; min-width: 0; }
.f-file-del { font-size: 24rpx; color: #E5484D; margin-left: 20rpx; flex-shrink: 0; }
.f-file-add { border: 1rpx dashed #C0C6D2; background: #FAFBFD; color: #7C8698; border-radius: 8rpx; padding: 20rpx; text-align: center; font-size: 26rpx; }
.f-file-add.err { border-color: #E5484D; background: #FDF3F3; color: #E5484D; }
/* åº•部 */
.bottom-bar { position: fixed; left: 0; right: 0; bottom: 0; background: #fff; border-top: 1rpx solid #EBEDF1; padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom)); display: flex; gap: 18rpx; }
.btn-draft { flex: 1; background: #fff; color: #1F4788; border: 1rpx solid #1F4788; }
.btn-submit { flex: 1.4; background: linear-gradient(90deg, #16345e, #1F4788 55%, #2a5aa8); color: #fff; box-shadow: 0 8rpx 20rpx rgba(31, 71, 136, 0.28); }
.btn-submit[disabled] { opacity: .6; }
</style>
src/pages/register/register.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,238 @@
<template>
  <view class="page">
    <view class="brand">
      <image class="brand-watermark" src="/static/logo-emblem-white.png" mode="aspectFit" />
      <image class="brand-logo" src="/static/logo-head-white.png" mode="aspectFit" />
      <view class="brand-title">注册账号</view>
      <view class="brand-sub">扫描班级二维码进入,填写学号与手机号并设置密码</view>
    </view>
    <view class="card">
      <!-- æ‰«ç ç­çº§å±•示 -->
      <view v-if="classInfo.className" class="class-banner">
        <text class="class-banner-label">你正在加入</text>
        <text class="class-banner-name">{{ [classInfo.collegeName, classInfo.majorName, classInfo.className].filter(Boolean).join(' Â· ') }}</text>
      </view>
      <!-- æœªæ‰«ç ï¼šæ‰‹åŠ¨é€‰æ‹©ç­çº§ -->
      <view v-else-if="!checkingCode" class="field" :class="{ 'field-err': errors.classId }">
        <text class="label">所在班级</text>
        <picker mode="selector" :range="classLabels" :value="classIndex" @change="onClassChange">
          <view class="picker" :class="{ ph: classIndex < 0 }">
            {{ classIndex >= 0 ? classLabels[classIndex] : '请选择你的班级(学院·专业·班级)' }}
          </view>
        </picker>
        <view v-if="errors.classId" class="err-text">{{ errors.classId }}</view>
        <view v-else class="class-tip">拿不准班级时,请咨询班主任;扫码注册可自动带入班级</view>
      </view>
      <view class="field" :class="{ 'field-err': errors.studentNo }">
        <text class="label">学号</text>
        <input class="input" v-model="form.studentNo" placeholder="请输入学号" placeholder-class="ph" @input="clearErr('studentNo')" />
        <view v-if="errors.studentNo" class="err-text">{{ errors.studentNo }}</view>
      </view>
      <view class="field" :class="{ 'field-err': errors.name }">
        <text class="label">姓名</text>
        <input class="input" v-model="form.name" placeholder="请输入真实姓名" placeholder-class="ph" @input="clearErr('name')" />
        <view v-if="errors.name" class="err-text">{{ errors.name }}</view>
      </view>
      <view class="field" :class="{ 'field-err': errors.phone }">
        <text class="label">手机号</text>
        <input class="input" v-model="form.phone" type="number" maxlength="11" placeholder="本人手机号(必填,用于找回密码)" placeholder-class="ph" @input="clearErr('phone')" />
        <view v-if="errors.phone" class="err-text">{{ errors.phone }}</view>
      </view>
      <view class="field" :class="{ 'field-err': errors.password }">
        <text class="label">设置密码</text>
        <input class="input" v-model="form.password" type="password" placeholder="8-20位,须含字母和数字" placeholder-class="ph" @input="clearErr('password')" />
        <view v-if="errors.password" class="err-text">{{ errors.password }}</view>
      </view>
      <view class="field" :class="{ 'field-err': errors.confirm }">
        <text class="label">确认密码</text>
        <input class="input" v-model="form.confirm" type="password" placeholder="请再次输入密码" placeholder-class="ph" @input="clearErr('confirm')" />
        <view v-if="errors.confirm" class="err-text">{{ errors.confirm }}</view>
      </view>
      <view class="field" v-if="captchaEnabled" :class="{ 'field-err': errors.code }">
        <text class="label">验证码</text>
        <view class="captcha-row">
          <input class="input captcha-input" v-model="form.code" placeholder="请输入验证码" placeholder-class="ph" maxlength="6" @input="clearErr('code')" />
          <image class="captcha-img" :src="captchaImg" mode="aspectFit" @click="loadCaptcha" />
        </view>
        <view v-if="errors.code" class="err-text">{{ errors.code }}</view>
      </view>
      <button class="btn btn-primary btn-block" :loading="submitting" :disabled="submitting" @click="doRegister">
        {{ submitting ? '提交中…' : '注册并开始填报' }}
      </button>
      <view class="links">
        <text class="link" @click="go('/pages/login/login')">已有账号?去登录</text>
      </view>
      <view class="tip">注册即代表承诺所填信息与班级真实准确;学号与姓名不可重复注册</view>
    </view>
  </view>
</template>
<script>
import { getCaptcha, accountRegister, resolveBind, getRegClasses } from '@/api/auth.js'
import { setToken } from '@/utils/request.js'
const BIND_CODE_KEY = '***'
export default {
  data() {
    return {
      submitting: false,
      checkingCode: true,
      bindCode: '',
      classInfo: {},
      // æœªæ‰«ç æ—¶çš„班级自选
      regClasses: [],
      classIndex: -1,
      form: { studentNo: '', name: '', phone: '', password: '', confirm: '', code: '', uuid: '' },
      errors: {},
      captchaEnabled: true,
      captchaImg: '',
    }
  },
  computed: {
    classLabels() {
      return this.regClasses.map((c) => c.label)
    },
  },
  async onLoad() {
    this.loadCaptcha()
    this.bindCode = uni.getStorageSync(BIND_CODE_KEY) || ''
    if (this.bindCode) {
      try {
        const res = await resolveBind(this.bindCode)
        this.classInfo = res.data || {}
      } catch (e) {
        this.bindCode = '' // ç æ— æ•ˆï¼šé™çº§ä¸ºæ‰‹åŠ¨é€‰ç­
      }
    }
    if (!this.bindCode) {
      try {
        const res = await getRegClasses()
        this.regClasses = res.data || []
      } catch (e) { this.regClasses = [] }
    }
    this.checkingCode = false
  },
  methods: {
    onClassChange(e) {
      this.classIndex = Number(e.detail.value)
      if (this.errors.classId) delete this.errors.classId
    },
    async loadCaptcha() {
      try {
        const res = await getCaptcha()
        this.captchaEnabled = res.captchaEnabled !== false
        this.captchaImg = res.img ? 'data:image/jpg;base64,' + res.img : ''
        this.form.uuid = res.uuid || ''
        this.form.code = ''
      } catch (e) { /* ignore */ }
    },
    clearErr(k) { if (this.errors[k]) delete this.errors[k] },
    validate() {
      const errs = {}
      if (!this.bindCode && this.classIndex < 0) errs.classId = '请选择你的班级'
      if (!this.form.studentNo.trim()) errs.studentNo = '请输入学号'
      if (!this.form.name.trim()) errs.name = '请输入姓名'
      if (!/^1[3-9]\d{9}$/.test(this.form.phone)) errs.phone = '请输入11位手机号'
      const p = this.form.password
      if (!p) errs.password = '请设置密码'
      else if (!/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d!@#$%^&*_.\-+=?]{8,20}$/.test(p)) errs.password = '8-20位,须同时包含字母和数字'
      else if (p === this.form.studentNo.trim()) errs.password = '密码不能与学号相同'
      if (!this.form.confirm) errs.confirm = '请再次输入密码'
      else if (this.form.confirm !== p) errs.confirm = '两次输入的密码不一致'
      if (this.captchaEnabled && !this.form.code.trim()) errs.code = '请输入验证码'
      this.errors = errs
      return !Object.keys(errs).length
    },
    async doRegister() {
      if (!this.validate()) return
      this.submitting = true
      try {
        const payload = {
          studentNo: this.form.studentNo.trim(),
          name: this.form.name.trim(),
          phone: this.form.phone.trim(),
          password: this.form.password,
          code: this.form.code.trim(),
          uuid: this.form.uuid,
        }
        // æ‰«ç ä¼˜å…ˆï¼›æœªæ‰«ç åˆ™æºå¸¦æ‰‹åŠ¨é€‰æ‹©çš„ç­çº§
        if (this.bindCode) payload.bindCode = this.bindCode
        else payload.classId = String(this.regClasses[this.classIndex].classId)
        const res = await accountRegister(payload)
        setToken(res.data.token)
        uni.removeStorageSync(BIND_CODE_KEY)
        uni.showToast({ title: '注册成功', icon: 'success' })
        setTimeout(() => uni.reLaunch({ url: '/pages/index/index' }), 600)
      } catch (e) {
        if (this.captchaEnabled) this.loadCaptcha()
      } finally {
        this.submitting = false
      }
    },
    go(url) { uni.navigateTo({ url }) },
  },
}
</script>
<style scoped>
button { margin: 0; padding: 0; }
button::after { border: none; }
.page { min-height: 100vh; background: #EEF2F8; padding: 0 0 60rpx; box-sizing: border-box; }
.brand {
  position: relative;
  padding: 48rpx 44rpx 96rpx;
  overflow: hidden;
  background:
    radial-gradient(420rpx 260rpx at 88% -20%, rgba(120, 165, 225, 0.38), transparent 60%),
    linear-gradient(135deg, #16345e 0%, #1F4788 55%, #2a5aa8 100%);
  border-radius: 0 0 30rpx 30rpx;
}
.brand-watermark { position: absolute; right: -36rpx; bottom: -60rpx; width: 280rpx; height: 280rpx; opacity: 0.12; }
.brand-logo { width: 380rpx; height: 84rpx; display: block; }
.brand-title { position: relative; margin-top: 26rpx; font-size: 40rpx; font-weight: 700; color: #fff; letter-spacing: 8rpx; }
.brand-sub { position: relative; margin-top: 10rpx; font-size: 24rpx; color: rgba(255, 255, 255, 0.72); line-height: 1.5; }
.card { position: relative; z-index: 1; background: #fff; margin: -56rpx 24rpx 0; border-radius: 16rpx; padding: 40rpx 30rpx 44rpx; box-shadow: 0 12rpx 36rpx rgba(31, 71, 136, 0.12); }
/* æ‰«ç ç­çº§æ¨ªå¹… */
.class-banner { display: flex; flex-direction: column; background: #E8EFF9; border: 1rpx solid #D5E2F5; border-radius: 12rpx; padding: 20rpx 24rpx; margin-bottom: 30rpx; }
.class-banner-label { font-size: 22rpx; color: #7C8698; }
.class-banner-name { margin-top: 6rpx; font-size: 28rpx; font-weight: 600; color: #1F4788; }
.picker { height: 88rpx; line-height: 88rpx; background: #fff; border: 1rpx solid #DCDFE6; border-radius: 8rpx; padding: 0 22rpx; font-size: 29rpx; color: #1F2D3D; box-sizing: border-box; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.field-err .picker { border-color: #E5484D; background: #FDF3F3; }
.class-tip { margin-top: 10rpx; font-size: 22rpx; color: #B4BAC6; }
.field { margin-bottom: 28rpx; }
.label { display: block; font-size: 27rpx; color: #303133; margin-bottom: 12rpx; }
.field-err .label { color: #C03; }
.input { height: 88rpx; line-height: 88rpx; background: #fff; border: 1rpx solid #DCDFE6; border-radius: 8rpx; padding: 0 22rpx; font-size: 29rpx; color: #1F2D3D; }
.input.err, .field-err .input { border-color: #E5484D; background: #FDF3F3; }
.err-text { margin-top: 8rpx; color: #E5484D; font-size: 24rpx; }
.ph { color: #C0C4CC; }
.captcha-row { display: flex; align-items: center; }
.captcha-input { flex: 1; }
.captcha-img { width: 200rpx; height: 88rpx; margin-left: 20rpx; border: 1rpx solid #DCDFE6; border-radius: 8rpx; background: #F0F2F6; }
.btn { height: 88rpx; line-height: 88rpx; border-radius: 12rpx; font-size: 30rpx; letter-spacing: 4rpx; text-align: center; box-sizing: border-box; }
.btn-primary { background: linear-gradient(90deg, #16345e, #1F4788 55%, #2a5aa8); color: #fff; box-shadow: 0 8rpx 20rpx rgba(31, 71, 136, 0.28); }
.btn-block { width: 100%; }
.btn[disabled] { opacity: .6; }
.btn-primary[disabled] { color: #fff; }
.links { display: flex; justify-content: center; margin-top: 26rpx; }
.link { color: #1F4788; font-size: 26rpx; }
.tip { margin-top: 20rpx; text-align: center; font-size: 23rpx; color: #B4BAC6; }
</style>
src/permission.js
ÎļþÒÑɾ³ý
src/plugins/auth.js
ÎļþÒÑɾ³ý
src/plugins/cache.js
ÎļþÒÑɾ³ý
src/plugins/download.js
ÎļþÒÑɾ³ý
src/plugins/index.js
ÎļþÒÑɾ³ý
src/plugins/modal.js
ÎļþÒÑɾ³ý
src/plugins/tab.js
ÎļþÒÑɾ³ý
src/router/index.js
ÎļþÒÑɾ³ý
src/settings.js
ÎļþÒÑɾ³ý
src/shime-uni.d.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
export {};
declare module "vue" {
  type Hooks = App.AppInstance & Page.PageInstance;
  interface ComponentCustomOptions extends Hooks {}
}
src/static/logo-emblem-white.png
src/static/logo-head-white.png
src/static/logo-navy.png
src/static/logo.png
src/store/index.js
ÎļþÒÑɾ³ý
src/store/modules/app.js
ÎļþÒÑɾ³ý
src/store/modules/dict.js
ÎļþÒÑɾ³ý
src/store/modules/permission.js
ÎļþÒÑɾ³ý
src/store/modules/settings.js
ÎļþÒÑɾ³ý
src/store/modules/tagsView.js
ÎļþÒÑɾ³ý
src/store/modules/user.js
ÎļþÒÑɾ³ý
src/uni.scss
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,76 @@
/**
 * è¿™é‡Œæ˜¯uni-app内置的常用样式变量
 *
 * uni-app å®˜æ–¹æ‰©å±•插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
 * å¦‚果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import è¿™ä¸ªæ–‡ä»¶ï¼‰ï¼Œæ–¹ä¾¿ç”¨æˆ·é€šè¿‡æ­ç§¯æœ¨çš„æ–¹å¼å¼€å‘整体风格一致的App
 *
 */
/**
 * å¦‚果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
 *
 * å¦‚果你的项目同样使用了scss预处理,你也可以直接在你的 scss ä»£ç ä¸­ä½¿ç”¨å¦‚下变量,同时无需 import è¿™ä¸ªæ–‡ä»¶
 */
/* é¢œè‰²å˜é‡ */
/* è¡Œä¸ºç›¸å…³é¢œè‰² */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* æ–‡å­—基本颜色 */
$uni-text-color: #333; // åŸºæœ¬è‰²
$uni-text-color-inverse: #fff; // åè‰²
$uni-text-color-grey: #999; // è¾…助灰色,如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable: #c0c0c0;
/* èƒŒæ™¯é¢œè‰² */
$uni-bg-color: #fff;
$uni-bg-color-grey: #f8f8f8;
$uni-bg-color-hover: #f1f1f1; // ç‚¹å‡»çŠ¶æ€é¢œè‰²
$uni-bg-color-mask: rgba(0, 0, 0, 0.4); // é®ç½©é¢œè‰²
/* è¾¹æ¡†é¢œè‰² */
$uni-border-color: #c8c7cc;
/* å°ºå¯¸å˜é‡ */
/* æ–‡å­—尺寸 */
$uni-font-size-sm: 12px;
$uni-font-size-base: 14px;
$uni-font-size-lg: 16;
/* å›¾ç‰‡å°ºå¯¸ */
$uni-img-size-sm: 20px;
$uni-img-size-base: 26px;
$uni-img-size-lg: 40px;
/* Border Radius */
$uni-border-radius-sm: 2px;
$uni-border-radius-base: 3px;
$uni-border-radius-lg: 6px;
$uni-border-radius-circle: 50%;
/* æ°´å¹³é—´è· */
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
/* åž‚直间距 */
$uni-spacing-col-sm: 4px;
$uni-spacing-col-base: 8px;
$uni-spacing-col-lg: 12px;
/* é€æ˜Žåº¦ */
$uni-opacity-disabled: 0.3; // ç»„件禁用态的透明度
/* æ–‡ç« åœºæ™¯ç›¸å…³ */
$uni-color-title: #2c405a; // æ–‡ç« æ ‡é¢˜é¢œè‰²
$uni-font-size-title: 20px;
$uni-color-subtitle: #555; // äºŒçº§æ ‡é¢˜é¢œè‰²
$uni-font-size-subtitle: 18px;
$uni-color-paragraph: #3f536e; // æ–‡ç« æ®µè½é¢œè‰²
$uni-font-size-paragraph: 15px;
src/utils/auth.js
ÎļþÒÑɾ³ý
src/utils/dict.js
ÎļþÒÑɾ³ý
src/utils/dynamicTitle.js
ÎļþÒÑɾ³ý
src/utils/errorCode.js
ÎļþÒÑɾ³ý
src/utils/generator/config.js
ÎļþÒÑɾ³ý
src/utils/generator/css.js
ÎļþÒÑɾ³ý
src/utils/generator/drawingDefalut.js
ÎļþÒÑɾ³ý
src/utils/generator/html.js
ÎļþÒÑɾ³ý
src/utils/generator/icon.json
ÎļþÒÑɾ³ý
src/utils/generator/js.js
ÎļþÒÑɾ³ý
src/utils/generator/render.js
ÎļþÒÑɾ³ý
src/utils/index.js
ÎļþÒÑɾ³ý
src/utils/jsencrypt.js
ÎļþÒÑɾ³ý
src/utils/permission.js
ÎļþÒÑɾ³ý
src/utils/region.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
/**
 * è¡Œæ”¿åŒºåˆ’数据(省/市两级)
 *
 * ç”¨é€”:填表配置中「省份」「城市」两种字段类型的选项来源,城市随省份二级联动。
 * å–值一律用中文名称(与 companyNature / industryType ç­‰å­—段存中文值的约定一致),
 * ä¾¿äºŽåˆ—表直读与 Excel å¯¼å‡ºï¼Œæ— éœ€å†åšç å€¼ç¿»è¯‘。
 *
 * æ•°æ®ä¸ºé™æ€å†…置:省市两级区划极少变动,如遇调整直接改本文件即可。
 *
 * æ³¨æ„ï¼šæœ¬æ–‡ä»¶ä¸Ž ruoyi-ui/src/utils/region.js å†…容一致(两个工程独立打包,无法共享模块)。
 *       ä¿®æ”¹è¡Œæ”¿åŒºåˆ’数据时请同步两边,否则后台配置的可选项与小程序端会对不上。
 */
/** çœçº§è¡Œæ”¿åŒºï¼ˆ34 ä¸ªï¼š23 çœ + 5 è‡ªæ²»åŒº + 4 ç›´è¾–市 + 2 ç‰¹åˆ«è¡Œæ”¿åŒºï¼‰ */
export const PROVINCES = [
  '北京市', '天津市', '河北省', '山西省', '内蒙古自治区',
  '辽宁省', '吉林省', '黑龙江省', '上海市', '江苏省',
  '浙江省', '安徽省', '福建省', '江西省', '山东省',
  '河南省', '湖北省', '湖南省', '广东省', '广西壮族自治区',
  '海南省', '重庆市', '四川省', '贵州省', '云南省',
  '西藏自治区', '陕西省', '甘肃省', '青海省', '宁夏回族自治区',
  '新疆维吾尔自治区', '台湾省', '香港特别行政区', '澳门特别行政区'
]
/** çœ â†’ åœ°å¸‚。直辖市列所辖行政区、港澳列区/堂区、台湾列县市(口径与附表《省市名称》一致) */
export const CITIES = {
  åŒ—京市: ['东城区', '西城区', '朝阳区', '丰台区', '石景山区', '海淀区', '门头沟区', '房山区', '通州区', '顺义区', '昌平区', '大兴区', '怀柔区', '平谷区', '密云区', '延庆区'],
  å¤©æ´¥å¸‚: ['和平区', '河东区', '河西区', '南开区', '河北区', '红桥区', '东丽区', '西青区', '津南区', '北辰区', '武清区', '宝坻区', '滨海新区', '宁河区', '静海区', '蓟州区'],
  ä¸Šæµ·å¸‚: ['黄浦区', '徐汇区', '长宁区', '静安区', '普陀区', '虹口区', '杨浦区', '闵行区', '宝山区', '嘉定区', '浦东新区', '金山区', '松江区', '青浦区', '奉贤区', '崇明区'],
  é‡åº†å¸‚: ['万州区', '涪陵区', '渝中区', '大渡口区', '江北区', '沙坪坝区', '九龙坡区', '南岸区', '北碚区', '綦江区', '大足区', '渝北区', '巴南区', '黔江区', '长寿区', '江津区', '合川区', '永川区', '南川区', '璧山区', '铜梁区', '潼南区', '荣昌区', '开州区', '梁平区', '武隆区', '城口县', '丰都县', '垫江县', '忠县', '云阳县', '奉节县', '巫山县', '巫溪县', '石柱土家族自治县', '秀山土家族苗族自治县', '酉阳土家族苗族自治县', '彭水苗族土家族自治县'],
  æ²³åŒ—省: ['石家庄市', '唐山市', '秦皇岛市', '邯郸市', '邢台市', '保定市', '张家口市', '承德市', '沧州市', '廊坊市', '衡水市'],
  å±±è¥¿çœ: ['太原市', '大同市', '阳泉市', '长治市', '晋城市', '朔州市', '晋中市', '运城市', '忻州市', '临汾市', '吕梁市'],
  å†…蒙古自治区: ['呼和浩特市', '包头市', '乌海市', '赤峰市', '通辽市', '鄂尔多斯市', '呼伦贝尔市', '巴彦淖尔市', '乌兰察布市', '兴安盟', '锡林郭勒盟', '阿拉善盟'],
  è¾½å®çœ: ['沈阳市', '大连市', '鞍山市', '抚顺市', '本溪市', '丹东市', '锦州市', '营口市', '阜新市', '辽阳市', '盘锦市', '铁岭市', '朝阳市', '葫芦岛市'],
  å‰æž—省: ['长春市', '吉林市', '四平市', '辽源市', '通化市', '白山市', '松原市', '白城市', '延边朝鲜族自治州'],
  é»‘龙江省: ['哈尔滨市', '齐齐哈尔市', '鸡西市', '鹤岗市', '双鸭山市', '大庆市', '伊春市', '佳木斯市', '七台河市', '牡丹江市', '黑河市', '绥化市', '大兴安岭地区'],
  æ±Ÿè‹çœ: ['南京市', '无锡市', '徐州市', '常州市', '苏州市', '南通市', '连云港市', '淮安市', '盐城市', '扬州市', '镇江市', '泰州市', '宿迁市'],
  æµ™æ±Ÿçœ: ['杭州市', '宁波市', '温州市', '嘉兴市', '湖州市', '绍兴市', '金华市', '衢州市', '舟山市', '台州市', '丽水市'],
  å®‰å¾½çœ: ['合肥市', '芜湖市', '蚌埠市', '淮南市', '马鞍山市', '淮北市', '铜陵市', '安庆市', '黄山市', '滁州市', '阜阳市', '宿州市', '六安市', '亳州市', '池州市', '宣城市'],
  ç¦å»ºçœ: ['福州市', '厦门市', '莆田市', '三明市', '泉州市', '漳州市', '南平市', '龙岩市', '宁德市'],
  æ±Ÿè¥¿çœ: ['南昌市', '景德镇市', '萍乡市', '九江市', '新余市', '鹰潭市', '赣州市', '吉安市', '宜春市', '抚州市', '上饶市'],
  å±±ä¸œçœ: ['济南市', '青岛市', '淄博市', '枣庄市', '东营市', '烟台市', '潍坊市', '济宁市', '泰安市', '威海市', '日照市', '临沂市', '德州市', '聊城市', '滨州市', '菏泽市'],
  æ²³å—省: ['郑州市', '开封市', '洛阳市', '平顶山市', '安阳市', '鹤壁市', '新乡市', '焦作市', '濮阳市', '许昌市', '漯河市', '三门峡市', '南阳市', '商丘市', '信阳市', '周口市', '驻马店市', '济源市'],
  æ¹–北省: ['武汉市', '黄石市', '十堰市', '宜昌市', '襄阳市', '鄂州市', '荆门市', '孝感市', '荆州市', '黄冈市', '咸宁市', '随州市', '恩施土家族苗族自治州', '仙桃市', '潜江市', '天门市', '神农架林区'],
  æ¹–南省: ['长沙市', '株洲市', '湘潭市', '衡阳市', '邵阳市', '岳阳市', '常德市', '张家界市', '益阳市', '郴州市', '永州市', '怀化市', '娄底市', '湘西土家族苗族自治州'],
  å¹¿ä¸œçœ: ['广州市', '韶关市', '深圳市', '珠海市', '汕头市', '佛山市', '江门市', '湛江市', '茂名市', '肇庆市', '惠州市', '梅州市', '汕尾市', '河源市', '阳江市', '清远市', '东莞市', '中山市', '潮州市', '揭阳市', '云浮市'],
  å¹¿è¥¿å£®æ—è‡ªæ²»åŒº: ['南宁市', '柳州市', '桂林市', '梧州市', '北海市', '防城港市', '钦州市', '贵港市', '玉林市', '百色市', '贺州市', '河池市', '来宾市', '崇左市'],
  æµ·å—省: ['海口市', '三亚市', '三沙市', '儋州市'],
  å››å·çœ: ['成都市', '自贡市', '攀枝花市', '泸州市', '德阳市', '绵阳市', '广元市', '遂宁市', '内江市', '乐山市', '南充市', '眉山市', '宜宾市', '广安市', '达州市', '雅安市', '巴中市', '资阳市', '阿坝藏族羌族自治州', '甘孜藏族自治州', '凉山彝族自治州'],
  è´µå·žçœ: ['贵阳市', '六盘水市', '遵义市', '安顺市', '毕节市', '铜仁市', '黔西南布依族苗族自治州', '黔东南苗族侗族自治州', '黔南布依族苗族自治州'],
  äº‘南省: ['昆明市', '曲靖市', '玉溪市', '保山市', '昭通市', '丽江市', '普洱市', '临沧市', '楚雄彝族自治州', '红河哈尼族彝族自治州', '文山壮族苗族自治州', '西双版纳傣族自治州', '大理白族自治州', '德宏傣族景颇族自治州', '怒江傈僳族自治州', '迪庆藏族自治州'],
  è¥¿è—è‡ªæ²»åŒº: ['拉萨市', '日喀则市', '昌都市', '林芝市', '山南市', '那曲市', '阿里地区'],
  é™•西省: ['西安市', '铜川市', '宝鸡市', '咸阳市', '渭南市', '延安市', '汉中市', '榆林市', '安康市', '商洛市'],
  ç”˜è‚ƒçœ: ['兰州市', '嘉峪关市', '金昌市', '白银市', '天水市', '武威市', '张掖市', '平凉市', '酒泉市', '庆阳市', '定西市', '陇南市', '临夏回族自治州', '甘南藏族自治州'],
  é’海省: ['西宁市', '海东市', '海北藏族自治州', '黄南藏族自治州', '海南藏族自治州', '果洛藏族自治州', '玉树藏族自治州', '海西蒙古族藏族自治州'],
  å®å¤å›žæ—è‡ªæ²»åŒº: ['银川市', '石嘴山市', '吴忠市', '固原市', '中卫市'],
  æ–°ç–†ç»´å¾å°”自治区: ['乌鲁木齐市', '克拉玛依市', '吐鲁番市', '哈密市', '昌吉回族自治州', '博尔塔拉蒙古自治州', '巴音郭楞蒙古自治州', '阿克苏地区', '克孜勒苏柯尔克孜自治州', '喀什地区', '和田地区', '伊犁哈萨克自治州', '塔城地区', '阿勒泰地区', '石河子市', '阿拉尔市', '图木舒克市', '五家渠市', '北屯市', '铁门关市', '双河市', '可克达拉市', '昆玉市', '胡杨河市'],
  å°æ¹¾çœ: ['台北', '高雄', '台南', '台中', '金门', '南投', '基隆', '新竹', '嘉义', '新北', '宜兰', '桃园', '苗栗', '彰化', '云林', '屏东', '台东', '花莲', '澎湖', '连江'],
  é¦™æ¸¯ç‰¹åˆ«è¡Œæ”¿åŒº: ['中西区', '湾仔区', '东区', '南区', '油尖旺区', '深水埗区', '九龙城区', '黄大仙区', '观塘区', '荃湾区', '屯门区', '元朗区', '北区', '大埔区', '西贡区', '沙田区', '葵青区', '离岛区'],
  æ¾³é—¨ç‰¹åˆ«è¡Œæ”¿åŒº: ['花地玛堂区', '花王堂区', '望德堂区', '大堂区', '风顺堂区', '嘉模堂区', '路凼填海区', '圣方济各堂区']
}
/** çœä¸‹æ‹‰é€‰é¡¹ */
export const PROVINCE_OPTIONS = PROVINCES.map(p => ({ value: p, label: p }))
/** å–某省下的地市;省份为空或无数据时返回空数组。容错简写:如「江苏」自动按「江苏省」解析 */
export function citiesOf(province) {
  if (!province) return []
  if (CITIES[province]) return CITIES[province]
  const guess = [province + '省', province + '市'].find(k => CITIES[k])
  return guess ? CITIES[guess] : []
}
/** åœ°å¸‚下拉选项(可带自定义首项,如「其他」) */
export function cityOptions(province) {
  return citiesOf(province).map(c => ({ value: c, label: c }))
}
src/utils/request.js
@@ -1,152 +1,114 @@
import axios from 'axios'
import { ElNotification , ElMessageBox, ElMessage, ElLoading } from 'element-plus'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { tansParams, blobValidate } from '@/utils/ruoyi'
import cache from '@/plugins/cache'
import { saveAs } from 'file-saver'
import useUserStore from '@/store/modules/user'
let downloadLoadingInstance
// æ˜¯å¦æ˜¾ç¤ºé‡æ–°ç™»å½•
export let isRelogin = { show: false }
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// åˆ›å»ºaxios实例
const service = axios.create({
  // axios中请求配置有baseURL选项,表示请求URL公共部分
  baseURL: import.meta.env.VITE_APP_BASE_API,
  // è¶…æ—¶
  timeout: 60000
})
// request拦截器
service.interceptors.request.use(config => {
  // æ˜¯å¦éœ€è¦è®¾ç½® token
  const isToken = (config.headers || {}).isToken === false
  // æ˜¯å¦éœ€è¦é˜²æ­¢æ•°æ®é‡å¤æäº¤
  const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
  if (getToken() && !isToken) {
    config.headers['Authorization'] = 'Bearer ' + getToken() // è®©æ¯ä¸ªè¯·æ±‚携带自定义token è¯·æ ¹æ®å®žé™…情况自行修改
  }
  // get请求映射params参数
  if (config.method === 'get' && config.params) {
    let url = config.url + '?' + tansParams(config.params)
    url = url.slice(0, -1)
    config.params = {}
    config.url = url
  }
  if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
    const requestObj = {
      url: config.url,
      data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
      time: new Date().getTime()
    }
    const requestSize = Object.keys(JSON.stringify(requestObj)).length // è¯·æ±‚数据大小
    const limitSize = 5 * 1024 * 1024 // é™åˆ¶å­˜æ”¾æ•°æ®5M
    if (requestSize >= limitSize) {
      console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制,无法进行防重复提交验证。')
      return config
    }
    const sessionObj = cache.session.getJSON('sessionObj')
    if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
      cache.session.setJSON('sessionObj', requestObj)
    } else {
      const s_url = sessionObj.url                // è¯·æ±‚地址
      const s_data = sessionObj.data              // è¯·æ±‚数据
      const s_time = sessionObj.time              // è¯·æ±‚æ—¶é—´
      const interval = 1000                       // é—´é𔿗¶é—´(ms),小于此时间视为重复提交
      if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
        const message = '数据正在处理,请勿重复提交'
        console.warn(`[${s_url}]: ` + message)
        return Promise.reject(new Error(message))
      } else {
        cache.session.setJSON('sessionObj', requestObj)
      }
    }
  }
  return config
}, error => {
    console.log(error)
    Promise.reject(error)
})
// å“åº”拦截器
service.interceptors.response.use(res => {
    // æœªè®¾ç½®çŠ¶æ€ç åˆ™é»˜è®¤æˆåŠŸçŠ¶æ€
    const code = res.data.code || 200
    // èŽ·å–é”™è¯¯ä¿¡æ¯
    const msg = errorCode[code] || res.data.msg || errorCode['default']
    // äºŒè¿›åˆ¶æ•°æ®åˆ™ç›´æŽ¥è¿”回
    if (res.request.responseType ===  'blob' || res.request.responseType ===  'arraybuffer') {
      return res.data
    }
    if (code === 401) {
      if (!isRelogin.show) {
        isRelogin.show = true
        ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
          isRelogin.show = false
          useUserStore().logOut().then(() => {
            location.href = '/index'
          })
      }).catch(() => {
        isRelogin.show = false
      })
    }
      return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
    } else if (code === 500) {
      ElMessage({ message: msg, type: 'error' })
      return Promise.reject(new Error(msg))
    } else if (code === 601) {
      ElMessage({ message: msg, type: 'warning' })
      return Promise.reject(new Error(msg))
    } else if (code !== 200) {
      ElNotification.error({ title: msg })
      return Promise.reject('error')
    } else {
      return  Promise.resolve(res.data)
    }
  },
  error => {
    console.log('err' + error)
    let { message } = error
    if (message == "Network Error") {
      message = "后端接口连接异常"
    } else if (message.includes("timeout")) {
      message = "系统接口请求超时"
    } else if (message.includes("Request failed with status code")) {
      message = "系统接口" + message.substr(message.length - 3) + "异常"
    }
    ElMessage({ message: message, type: 'error', duration: 5 * 1000 })
    return Promise.reject(error)
  }
)
// é€šç”¨ä¸‹è½½æ–¹æ³•
export function download(url, params, filename, config) {
  downloadLoadingInstance = ElLoading.service({ text: "正在下载数据,请稍候", background: "rgba(0, 0, 0, 0.7)", })
  return service.post(url, params, {
    transformRequest: [(params) => { return tansParams(params) }],
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    responseType: 'blob',
    ...config
  }).then(async (data) => {
    const isBlob = blobValidate(data)
    if (isBlob) {
      const blob = new Blob([data])
      saveAs(blob, filename)
    } else {
      const resText = await data.text()
      const rspObj = JSON.parse(resText)
      const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
      ElMessage.error(errMsg)
    }
    downloadLoadingInstance.close()
  }).catch((r) => {
    console.error(r)
    ElMessage.error('下载文件出现错误,请联系管理员!')
    downloadLoadingInstance.close()
  })
}
export default service
/**
 * è¯·æ±‚封装(基于 uni.request,支持 token、错误统一处理)
 */
import config from '@/config.js'
// å­˜å‚¨ token çš„ key
const TOKEN_KEY = 'cj_student_token'
export function getToken() {
  return uni.getStorageSync(TOKEN_KEY)
}
export function setToken(t) {
  uni.setStorageSync(TOKEN_KEY, t)
}
export function clearToken() {
  uni.removeStorageSync(TOKEN_KEY)
}
function request(method, url, data = {}, options = {}) {
  return new Promise((resolve, reject) => {
    const token = getToken()
    uni.request({
      url: config.baseUrl + url,
      method,
      data,
      header: {
        'Content-Type': 'application/json',
        ...(token ? { Authorization: 'Bearer ' + token } : {}),
        ...(options.header || {}),
      },
      success: (res) => {
        if (res.statusCode === 401) {
          clearToken()
          uni.showToast({ title: '请重新登录', icon: 'none' })
          uni.reLaunch({ url: '/pages/login/login' })
          reject(res.data)
          return
        }
        if (res.data && res.data.code === 200) {
          resolve(res.data)
        } else {
          // åŽç«¯ä»¥ HTTP 200 + body.code 401 è¡¨è¾¾ç™»å½•失效:同步清 token,跳登录页
          if (res.data && res.data.code === 401) {
            clearToken()
            uni.showToast({ title: '登录已失效,请重新登录', icon: 'none' })
            uni.reLaunch({ url: '/pages/login/login' })
          } else {
            uni.showToast({ title: (res.data && res.data.msg) || '请求失败', icon: 'none' })
          }
          reject(res.data)
        }
      },
      fail: (err) => {
        uni.showToast({ title: '网络异常,请检查后端连接', icon: 'none' })
        reject(err)
      },
    })
  })
}
/**
 * ä¸Šä¼ å•个文件到 /miniapp/upload。
 * H5 å¯ä¼  file(input[type=file] é€‰ä¸­çš„ File å¯¹è±¡ï¼‰ï¼›å°ç¨‹åº/App ä¼  filePath(临时路径)。
 * åŽç«¯å“åº”为 { code, msg, data: { fileName, originalName } };
 * æˆåŠŸæ—¶ resolve å†…层 data({ fileName, originalName }),兼容个别旧结构的顶层 fileName。
 */
export function uploadFile({ filePath, file }) {
  return new Promise((resolve, reject) => {
    const token = getToken()
    // uni-h5 çš„ uploadFile ç¼º filePath ä¼šå…ˆ reject("file error")(但 XHR ä»ä¼šå‘出,导致
    // ã€ŒåŽç«¯ä¼ æˆåŠŸã€å‰ç«¯æŠ¥å¤±è´¥ã€ï¼‰ï¼›H5 ä¼  File å¯¹è±¡æ—¶è¡¥ä¸€ä¸ª blob URL å…œåº•。
    let fp = filePath
    if (!fp && file) {
      try { fp = URL.createObjectURL(file) } catch (e) { /* éžæµè§ˆå™¨çŽ¯å¢ƒå¿½ç•¥ */ }
    }
    uni.uploadFile({
      url: config.baseUrl + '/miniapp/upload',
      filePath: fp,
      file,
      name: 'file',
      header: token ? { Authorization: 'Bearer ' + token } : {},
      success: (res) => {
        let d = res.data
        try { d = JSON.parse(res.data) } catch (e) { /* ä¿ç•™åŽŸå§‹æ–‡æœ¬ */ }
        if (res.statusCode === 401) {
          clearToken()
          uni.showToast({ title: '请重新登录', icon: 'none' })
          uni.reLaunch({ url: '/pages/login/login' })
          reject(d)
          return
        }
        if (d && d.code === 200) {
          // çœŸæ­£æœ‰ç”¨çš„æ˜¯ data å†…层;旧代码直接 resolve æ•´ä¸ªå“åº”体导致 res.fileName æ’为 undefined
          resolve(d.data || d)
        } else {
          uni.showToast({ title: (d && d.msg) || '上传失败', icon: 'none' })
          reject(d)
        }
      },
      fail: (err) => {
        uni.showToast({ title: '上传失败,请检查网络', icon: 'none' })
        reject(err)
      },
    })
  })
}
export default {
  get: (url, data, opts) => request('GET', url, data, opts),
  post: (url, data, opts) => request('POST', url, data, opts),
  put: (url, data, opts) => request('PUT', url, data, opts),
  delete: (url, data, opts) => request('DELETE', url, data, opts),
  upload: uploadFile,
}
src/utils/ruoyi.js
ÎļþÒÑɾ³ý
src/utils/scroll-to.js
ÎļþÒÑɾ³ý
src/utils/site.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
/**
 * ç«™ç‚¹æ–‡æ¡ˆï¼ˆåŽå°ã€Œå­—典管理 â†’ 2024级学生产教融合实践教学信息填报」驱动)
 *
 * æ–‡æ¡ˆç”± /miniapp/site-titles ä¸‹å‘,后台改完即时生效,前端不用重新打包。
 * æŽ¥å£æœªé€š / å­—典项被删 / å€¼ä¸ºç©ºæ—¶ï¼Œä¸€å¾‹å›žé€€ä¸‹é¢çš„内置默认,页面不会出现空白标题。
 * ä¸€æ¬¡ä¼šè¯åªè¯·æ±‚一次(并发调用共用同一个 pending Promise),失败不缓存、下次可重试。
 */
import { getSiteTitles } from '@/api/auth.js'
// å…œåº•文案:须与后端 MiniappController#siteTitles çš„ fallback ä¿æŒä¸€è‡´
export const DEFAULT_TITLES = {
  platformTitle: '产教融合实践教学管理平台',
  platformSubtitle: '江苏商贸职业学院 Â· å­¦ç”Ÿå®žè·µæ•™å­¦ä¿¡æ¯å¡«æŠ¥',
  loginSubtitle: '产教融合实践教学管理平台 Â· å­¦ç”Ÿè´¦å·',
}
let cache = null
let pending = null
/** å–站点文案(带缓存);永远 resolve,不会 reject */
export function getTitles() {
  if (cache) return Promise.resolve(cache)
  if (!pending) {
    pending = getSiteTitles()
      .then((res) => {
        cache = { ...DEFAULT_TITLES, ...(res.data || {}) }
        return cache
      })
      .catch(() => DEFAULT_TITLES)
      .then((v) => {
        pending = null
        return v
      })
  }
  return pending
}
src/utils/summarizeTable.js
ÎļþÒÑɾ³ý
src/utils/theme.js
ÎļþÒÑɾ³ý
src/utils/util.js
ÎļþÒÑɾ³ý
src/utils/validate.js
ÎļþÒÑɾ³ý
src/views/basicData/customerFile/index.vue
ÎļþÒÑɾ³ý
src/views/basicData/product/ImportExcel/index.vue
ÎļþÒÑɾ³ý
src/views/basicData/product/index.vue
ÎļþÒÑɾ³ý
src/views/basicData/supplierManage/index.vue
ÎļþÒÑɾ³ý
src/views/chatHome/chatHomeIndex/MobileChat.vue
ÎļþÒÑɾ³ý
src/views/chatHome/chatHomeIndex/ai-jz.js
ÎļþÒÑɾ³ý
src/views/chatHome/chatHomeIndex/ai-wd.js
ÎļþÒÑɾ³ý
src/views/chatHome/chatHomeIndex/home.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/approvalProcess/components/approvalDia.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/approvalProcess/fileList.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/approvalProcess/index.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/approvalProcess/index1.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/approvalProcess/index2.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/approvalProcess/index3.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/approvalProcess/index4.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/attendanceManagement/index.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/knowledgeBase/index.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/meetingBoard/index.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/noticeManagement/index.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/notificationManagement/index.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/officeSupplies/index.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/planTemplate/index.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/rpaManagement/index.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/sealManagement/index.vue
ÎļþÒÑɾ³ý
src/views/collaborativeApproval/warningSystem/index.vue
ÎļþÒÑɾ³ý
src/views/customerService/afterSalesHandling/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/customerService/afterSalesHandling/index.vue
ÎļþÒÑɾ³ý
src/views/customerService/feedbackRegistration/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/customerService/feedbackRegistration/index.vue
ÎļþÒÑɾ³ý
src/views/demo/fakePage/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/dynamicEnergySaving/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/energyArea/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/energyCockpit/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/energyPeriodTime/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/energyPower/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/energyPower/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/energyTrends/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/gasManagement/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/meterCollection/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/waterManagement/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/waterManagement/components/waterBillForm.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/waterManagement/index.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/waterManagement/waterBill.vue
ÎļþÒÑɾ³ý
src/views/energyManagement/waterManagement/waterTrends.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/brand/index.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/calibration/index.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/deviceInfo/index.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/gasTank/simple.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/iotMonitor/index.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/iotMonitor/indexWD.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/ledger/Form.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/ledger/Modal.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/ledger/index.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/measurementEquipment/components/calibrationDia.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/measurementEquipment/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/measurementEquipment/filesDia.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/measurementEquipment/index.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/repair/Form/MaintainForm.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/repair/Form/RepairForm.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/repair/Modal/MaintainModal.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/repair/Modal/RepairModal.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/repair/index.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/upkeep/Form/MaintenanceForm.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/upkeep/Form/PlanForm.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/upkeep/Modal/MaintenanceModal.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/upkeep/Modal/PlanModal.vue
ÎļþÒÑɾ³ý
src/views/equipmentManagement/upkeep/index.vue
ÎļþÒÑɾ³ý
src/views/error/401.vue
ÎļþÒÑɾ³ý
src/views/error/404.vue
ÎļþÒÑɾ³ý
src/views/example/DynamicTableExample.vue
ÎļþÒÑɾ³ý
src/views/example/SimpleExample.vue
ÎļþÒÑɾ³ý
src/views/fileManagement/bookshelf/detail.vue
ÎļþÒÑɾ³ý
src/views/fileManagement/bookshelf/index.vue
ÎļþÒÑɾ³ý
src/views/fileManagement/borrow/index.vue
ÎļþÒÑɾ³ý
src/views/fileManagement/document/attachmentManager.vue
ÎļþÒÑɾ³ý
src/views/fileManagement/document/index.vue
ÎļþÒÑɾ³ý
src/views/fileManagement/return/index.vue
ÎļþÒÑɾ³ý
src/views/fileManagement/statistics/index.vue
ÎļþÒÑɾ³ý
src/views/financialManagement/expenseManagement/Form.vue
ÎļþÒÑɾ³ý
src/views/financialManagement/expenseManagement/Modal.vue
ÎļþÒÑɾ³ý
src/views/financialManagement/expenseManagement/index.vue
ÎļþÒÑɾ³ý
src/views/financialManagement/financialStatements/index.vue
ÎļþÒÑɾ³ý
src/views/financialManagement/revenueManagement/Form.vue
ÎļþÒÑɾ³ý
src/views/financialManagement/revenueManagement/Modal.vue
ÎļþÒÑɾ³ý
src/views/financialManagement/revenueManagement/filesDia.vue
ÎļþÒÑɾ³ý
src/views/financialManagement/revenueManagement/index.vue
ÎļþÒÑɾ³ý
src/views/index.vue
ÎļþÒÑɾ³ý
src/views/inventoryManagement/dispatchLog/index.vue
ÎļþÒÑɾ³ý
src/views/inventoryManagement/index.vue
ÎļþÒÑɾ³ý
src/views/inventoryManagement/issueManagement/index.vue
ÎļþÒÑɾ³ý
src/views/inventoryManagement/receiptManagement/index.vue
ÎļþÒÑɾ³ý
src/views/inventoryManagement/stockManagement/index.vue
ÎļþÒÑɾ³ý
src/views/inventoryManagement/stockWarning/index.vue
ÎļþÒÑɾ³ý
src/views/lavorissue/ledger/Form.vue
ÎļþÒÑɾ³ý
src/views/lavorissue/ledger/Modal.vue
ÎļþÒÑɾ³ý
src/views/lavorissue/ledger/filesDia.vue
ÎļþÒÑɾ³ý
src/views/lavorissue/ledger/index.vue
ÎļþÒÑɾ³ý
src/views/lavorissue/statistics/index.vue
ÎļþÒÑɾ³ý
src/views/login.vue
ÎļþÒÑɾ³ý
src/views/monitor/cache/index.vue
ÎļþÒÑɾ³ý
src/views/monitor/cache/list.vue
ÎļþÒÑɾ³ý
src/views/monitor/druid/index.vue
ÎļþÒÑɾ³ý
src/views/monitor/job/index.vue
ÎļþÒÑɾ³ý
src/views/monitor/job/log.vue
ÎļþÒÑɾ³ý
src/views/monitor/logininfor/index.vue
ÎļþÒÑɾ³ý
src/views/monitor/online/index.vue
ÎļþÒÑɾ³ý
src/views/monitor/operlog/index.vue
ÎļþÒÑɾ³ý
src/views/monitor/server/index.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/analytics/index.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/contractManagement/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/contractManagement/filesDia.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/contractManagement/index.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/dimission/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/dimission/index.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/employeeRecord/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/employeeRecord/index.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/onboarding/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/onboarding/index.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/payrollManagement/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/payrollManagement/index.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/scheduling/index.vue
ÎļþÒÑɾ³ý
src/views/personnelManagement/selfService/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/arrivalManagement/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/invoiceEntry/components/ExpandTable.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/invoiceEntry/components/Modal.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/invoiceEntry/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/invoiceEntry/indexOld.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/paymentEntry/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/paymentHistory/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/paymentLedger/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/priceManagement/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/procurementInvoiceLedger/Form/EditForm.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/procurementInvoiceLedger/Modal/EditModal.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/procurementInvoiceLedger/Modal/UploadModal.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/procurementInvoiceLedger/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/procurementInvoiceLedger/indexOld.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/procurementLedger/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/purchaseOrder/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/qualityInspection/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/returnManagement/index.vue
ÎļþÒÑɾ³ý
src/views/procurementManagement/thePaymentLedger/index.vue
ÎļþÒÑɾ³ý
src/views/productManagement/productIdentifier/index.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/operationScheduling/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/operationScheduling/index.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/productionCosting/index.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/productionDispatching/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/productionDispatching/index.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/productionOrder/index.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/productionReporting/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/productionReporting/index.vue
ÎļþÒÑɾ³ý
src/views/productionManagement/safetyMonitoring/index.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/finalInspection/components/filesDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/finalInspection/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/finalInspection/components/inspectionFormDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/finalInspection/index.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/metricMaintenance/index.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/nonconformingManagement/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/nonconformingManagement/components/inspectionFormDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/nonconformingManagement/index.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/processInspection/components/filesDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/processInspection/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/processInspection/components/inspectionFormDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/processInspection/index.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/rawMaterialInspection/components/filesDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/rawMaterialInspection/components/formDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/rawMaterialInspection/components/inspectionFormDia.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/rawMaterialInspection/index.vue
ÎļþÒÑɾ³ý
src/views/qualityManagement/visualization/qualityDashboard.vue
ÎļþÒÑɾ³ý
src/views/redirect/index.vue
ÎļþÒÑɾ³ý
src/views/register.vue
ÎļþÒÑɾ³ý
src/views/reportAnalysis/projectProfit/index.vue
ÎļþÒÑɾ³ý
src/views/reportAnalysis/reportManagement.vue
ÎļþÒÑɾ³ý
src/views/reportAnalysis/reportManagement/index.vue
ÎļþÒÑɾ³ý
src/views/reportAnalysis/taxComparison/index.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/customerManagement/index.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/invoiceLedger/index.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/invoiceRegistration/index.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/orderManagement/index.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/paymentShipping/index.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/receiptPayment/index.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/receiptPaymentHistory/index.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/receiptPaymentLedger/index.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/salesLedger/fileList.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/salesLedger/index.vue
ÎļþÒÑɾ³ý
src/views/salesManagement/salespersonManagement/index.vue
ÎļþÒÑɾ³ý
src/views/system/config/index.vue
ÎļþÒÑɾ³ý
src/views/system/dept/index.vue
ÎļþÒÑɾ³ý
src/views/system/dict/data.vue
ÎļþÒÑɾ³ý
src/views/system/dict/index.vue
ÎļþÒÑɾ³ý
src/views/system/menu/index.vue
ÎļþÒÑɾ³ý
src/views/system/notice/index.vue
ÎļþÒÑɾ³ý
src/views/system/post/index.vue
ÎļþÒÑɾ³ý
src/views/system/role/authUser.vue
ÎļþÒÑɾ³ý
src/views/system/role/index.vue
ÎļþÒÑɾ³ý
src/views/system/role/selectUser.vue
ÎļþÒÑɾ³ý
src/views/system/user/authRole.vue
ÎļþÒÑɾ³ý
src/views/system/user/index.vue
ÎļþÒÑɾ³ý
src/views/system/user/profile/index.vue
ÎļþÒÑɾ³ý
src/views/system/user/profile/resetPwd.vue
ÎļþÒÑɾ³ý
src/views/system/user/profile/userAvatar.vue
ÎļþÒÑɾ³ý
src/views/system/user/profile/userInfo.vue
ÎļþÒÑɾ³ý
src/views/tideLogin.vue
ÎļþÒÑɾ³ý
src/views/tool/build/CodeTypeDialog.vue
ÎļþÒÑɾ³ý
src/views/tool/build/DraggableItem.vue
ÎļþÒÑɾ³ý
src/views/tool/build/IconsDialog.vue
ÎļþÒÑɾ³ý
src/views/tool/build/RightPanel.vue
ÎļþÒÑɾ³ý
src/views/tool/build/TreeNodeDialog.vue
ÎļþÒÑɾ³ý
src/views/tool/build/index.vue
ÎļþÒÑɾ³ý
src/views/tool/gen/basicInfoForm.vue
ÎļþÒÑɾ³ý
src/views/tool/gen/createTable.vue
ÎļþÒÑɾ³ý
src/views/tool/gen/editTable.vue
ÎļþÒÑɾ³ý
src/views/tool/gen/genInfoForm.vue
ÎļþÒÑɾ³ý
src/views/tool/gen/importTable.vue
ÎļþÒÑɾ³ý
src/views/tool/gen/index.vue
ÎļþÒÑɾ³ý
src/views/tool/swagger/index.vue
ÎļþÒÑɾ³ý
vite.config.js
@@ -1,82 +1,20 @@
import { defineConfig, loadEnv } from "vite";
import path from "path";
import createVitePlugins from "./vite/plugins";
// https://vitejs.dev/config/
export default defineConfig(({ mode, command }) => {
  const env = loadEnv(mode, process.cwd());
  const { VITE_APP_ENV } = env;
  const baseUrl =
    VITE_APP_ENV == "development"
      ? "http://114.132.189.42:8089" // å¼€å‘环境后端接口
      : "http://114.132.189.42:9032"; // ç”Ÿäº§çŽ¯å¢ƒåŽç«¯æŽ¥å£
  return {
    // éƒ¨ç½²ç”Ÿäº§çŽ¯å¢ƒå’Œå¼€å‘çŽ¯å¢ƒä¸‹çš„URL。
    // é»˜è®¤æƒ…况下,vite ä¼šå‡è®¾ä½ çš„应用是被部署在一个域名的根路径上
    // ä¾‹å¦‚ https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl ä¸º /admin/。
    base: VITE_APP_ENV === "production" ? "/" : "/",
    plugins: createVitePlugins(env, command === "build"),
    resolve: {
      // https://cn.vitejs.dev/config/#resolve-alias
      alias: {
        // è®¾ç½®è·¯å¾„
        "~": path.resolve(__dirname, "./"),
        // è®¾ç½®åˆ«å
        "@": path.resolve(__dirname, "./src"),
      },
      // https://cn.vitejs.dev/config/#resolve-extensions
      extensions: [".mjs", ".js", ".ts", ".jsx", ".tsx", ".json", ".vue"],
    },
    // æ‰“包配置
    build: {
      // https://vite.dev/config/build-options.html
      sourcemap: command === "build" ? false : "inline",
      outDir: "dist",
      assetsDir: "assets",
      chunkSizeWarningLimit: 2000,
      rollupOptions: {
        output: {
          chunkFileNames: "static/js/[name]-[hash].js",
          entryFileNames: "static/js/[name]-[hash].js",
          assetFileNames: "static/[ext]/[name]-[hash].[ext]",
        },
      },
    },
    // vite ç›¸å…³é…ç½®
    server: {
      port: 8001,
      host: true,
      open: true,
      proxy: {
        // https://cn.vitejs.dev/config/#server-proxy
        "/dev-api": {
          target: baseUrl,
          changeOrigin: true,
          rewrite: (p) => p.replace(/^\/dev-api/, ""),
        },
        // springdoc proxy
        "^/v3/api-docs/(.*)": {
          target: baseUrl,
          changeOrigin: true,
        },
      },
    },
    css: {
      postcss: {
        plugins: [
          {
            postcssPlugin: "internal:charset-removal",
            AtRule: {
              charset: (atRule) => {
                if (atRule.name === "charset") {
                  atRule.remove();
                }
              },
            },
          },
        ],
      },
    },
  };
});
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    uni(),
  ],
  // ä»…影响开发服务器(dev:h5),不影响 npm run build äº§ç‰©ã€‚
  // å­¦ç”Ÿç«¯ baseUrl å›ºå®šä¸º /prod-api(对应 nginx åä»£ï¼‰ï¼Œæœ¬åœ°å¼€å‘没有 nginx,
  // æ•…在此把 /prod-api è½¬å‘到本机后端并去掉前缀。
  server: {
    proxy: {
      '/prod-api': {
        target: 'http://localhost:18080',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/prod-api/, ''),
      },
    },
  },
})
vite/plugins/auto-import.js
ÎļþÒÑɾ³ý
vite/plugins/compression.js
ÎļþÒÑɾ³ý
vite/plugins/index.js
ÎļþÒÑɾ³ý
vite/plugins/setup-extend.js
ÎļþÒÑɾ³ý
vite/plugins/svg-icon.js
ÎļþÒÑɾ³ý