├── .gitignore ├── DEV.md ├── LICENSE ├── README.md ├── admin ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── .prettierrc.js ├── README.md ├── assets │ ├── font │ │ ├── iconfont.css │ │ ├── iconfont.ttf │ │ ├── iconfont.woff │ │ └── iconfont.woff2 │ ├── images │ │ ├── empty-design.png │ │ ├── login.png │ │ ├── no1.svg │ │ ├── no2.svg │ │ ├── no3.svg │ │ └── sub.png │ ├── script │ │ └── remoteData.ts │ └── style │ │ ├── common.less │ │ └── theme.less ├── components │ ├── Logo.vue │ ├── base │ │ ├── Color │ │ │ └── ColorPicker.vue │ │ ├── Date │ │ │ └── DatePicker.vue │ │ ├── Divider │ │ │ └── DividerV.vue │ │ ├── Editor │ │ │ └── Editor.vue │ │ ├── Empty │ │ │ └── Empty.vue │ │ ├── Modal │ │ │ ├── Rider.vue │ │ │ ├── Taker.vue │ │ │ └── User.vue │ │ ├── Picture │ │ │ └── Picture.vue │ │ ├── Search │ │ │ └── Search.vue │ │ ├── Tag │ │ │ └── Tag.vue │ │ ├── Upload │ │ │ ├── Upload.vue │ │ │ ├── UploadImage.vue │ │ │ └── UploadRichtext.vue │ │ ├── UserLink │ │ │ ├── AdminLink.vue │ │ │ ├── AgentLink.vue │ │ │ ├── RiderLink.vue │ │ │ ├── TakerLink.vue │ │ │ └── UserLink.vue │ │ ├── action │ │ │ └── Action.vue │ │ ├── index.js │ │ └── list │ │ │ └── HoverList.vue │ ├── config │ │ ├── AliConfig.vue │ │ ├── AppMch.vue │ │ ├── AppauthConfig.vue │ │ ├── HttpUrlModal.vue │ │ ├── MapConfig.vue │ │ ├── MySubscribe.vue │ │ ├── PubSubscribe.vue │ │ ├── SubscribeSetting.vue │ │ ├── SubscribeTmp.vue │ │ └── WxappSubscribe.vue │ ├── material │ │ ├── GroupEdit.vue │ │ ├── GroupMove.vue │ │ ├── PicGroup.vue │ │ ├── PicItem.vue │ │ └── RichtextItem.vue │ ├── official │ │ ├── layout │ │ │ ├── Header.vue │ │ │ ├── Main.vue │ │ │ └── SidebarForSchool.vue │ │ └── login │ │ │ ├── Account.vue │ │ │ ├── Qrcode.vue │ │ │ └── StyleBtn.vue │ ├── order │ │ ├── Cancel.vue │ │ ├── OrderExanded.vue │ │ ├── OrderHandleModal.vue │ │ └── lib │ │ │ ├── ClearInfo.vue │ │ │ ├── ErrandsInfo.vue │ │ │ ├── ExpressInfo.vue │ │ │ ├── MoveInfo.vue │ │ │ ├── PlayInfo.vue │ │ │ ├── PrintInfo.vue │ │ │ ├── RepairInfo.vue │ │ │ └── ShopGoodsInfo.vue │ ├── overview │ │ ├── OrderLine.vue │ │ ├── OrderLines.vue │ │ ├── OrderStatus.vue │ │ ├── TakerSort.vue │ │ ├── TotalData.vue │ │ ├── UserLine.vue │ │ └── UserLines.vue │ ├── rider │ │ ├── Receive.vue │ │ ├── Refuse.vue │ │ └── RefuseCash.vue │ ├── school │ │ ├── AreaEditModal.vue │ │ ├── AreaItem.vue │ │ ├── Areas.vue │ │ ├── BuildingEditModal.vue │ │ ├── BuildingItem.vue │ │ ├── Carousels.vue │ │ ├── Service.vue │ │ └── components │ │ │ ├── AddServiceModel.vue │ │ │ ├── ServiceInfo.vue │ │ │ ├── SortStyle.vue │ │ │ └── UpdateService.vue │ ├── service │ │ ├── ServiceItem.vue │ │ ├── components │ │ │ ├── ClearEditModal.vue │ │ │ ├── ErrandsModal.vue │ │ │ └── ExpressEditModel.vue │ │ └── lib │ │ │ ├── Errands.vue │ │ │ ├── Express.vue │ │ │ ├── Play.vue │ │ │ └── Software.vue │ ├── taker │ │ ├── Receive.vue │ │ └── Refuse.vue │ └── user │ │ ├── Avatar.vue │ │ ├── LabelList.vue │ │ └── RealnameModal.vue ├── config.js ├── content │ ├── hello.md │ └── help │ │ └── shortcut-key.md ├── layouts │ ├── choose.vue │ └── global.vue ├── nuxt.config.js ├── package.json ├── pages │ ├── config │ │ ├── agreementRider.vue │ │ ├── app.vue │ │ ├── cash.vue │ │ ├── cashSetting.vue │ │ ├── mapupload.vue │ │ ├── ordertype.vue │ │ ├── protocol.vue │ │ ├── setting.vue │ │ ├── share.vue │ │ ├── subscribe.vue │ │ ├── timeRequirement.vue │ │ ├── user.vue │ │ ├── wxsubscribe.vue │ │ └── wxsubscribeedit.vue │ ├── index.vue │ ├── init.vue │ ├── login.vue │ ├── material │ │ ├── picture.vue │ │ └── richtext │ │ │ ├── edit │ │ │ └── _type.vue │ │ │ └── index.vue │ ├── rider │ │ └── cash.vue │ ├── school │ │ ├── detail.vue │ │ ├── edit │ │ │ └── _type.vue │ │ ├── order │ │ │ ├── capitaltrend.vue │ │ │ └── orders.vue │ │ ├── page.vue │ │ └── taker │ │ │ ├── edit │ │ │ └── add.vue │ │ │ └── takers.vue │ └── user │ │ ├── admins.vue │ │ ├── edit │ │ └── _type.vue │ │ ├── pwd.vue │ │ ├── setpwd.vue │ │ ├── update.vue │ │ ├── users.vue │ │ └── wxapps.vue ├── plugins │ ├── antd-ui.js │ ├── api.ts │ ├── bus.ts │ ├── city.ts │ ├── config.ts │ ├── froala.js │ ├── http.ts │ ├── mixins │ │ ├── edit-mixin.vue │ │ ├── modal-mixin.vue │ │ ├── service-mixin.vue │ │ └── table-data-mixin.vue │ ├── oss.ts │ └── pages.json ├── static │ └── favicon.ico ├── store │ ├── README.md │ ├── index.ts │ ├── modules │ │ ├── file.ts │ │ ├── profile.ts │ │ ├── subscribe.ts │ │ └── system.ts │ └── version.ts ├── tsconfig.json └── vue-shim.d.ts ├── build.md ├── miniprogram ├── .gitignore ├── README.md ├── babel.config.js ├── package.json ├── postcss.config.js ├── public │ └── index.html ├── src │ ├── App.vue │ ├── assets │ │ ├── font │ │ │ ├── demo.css │ │ │ ├── iconfont.css │ │ │ ├── iconfont.ttf │ │ │ ├── iconfont.woff │ │ │ └── iconfont.woff2 │ │ ├── images │ │ │ └── empty.png │ │ └── style │ │ │ ├── common.scss │ │ │ └── service.scss │ ├── components │ │ ├── base │ │ │ ├── button │ │ │ │ └── Button.vue │ │ │ ├── empty │ │ │ │ └── Empty.vue │ │ │ ├── image │ │ │ │ └── image.vue │ │ │ ├── scroll │ │ │ │ └── ScrollX.vue │ │ │ ├── swiper │ │ │ │ └── Swiper.vue │ │ │ ├── tag │ │ │ │ └── Tag.vue │ │ │ └── watermark │ │ │ │ └── Watermark.vue │ │ ├── location │ │ │ ├── LocationBar.vue │ │ │ ├── LocationItem.vue │ │ │ └── searchBar.vue │ │ ├── mine │ │ │ ├── AddressChooseLocation.vue │ │ │ ├── AddressDetault.vue │ │ │ ├── AddressItem.vue │ │ │ ├── AddressSchoolAreaPicker.vue │ │ │ ├── AddressSchoolPicker.vue │ │ │ ├── AddressTab.vue │ │ │ ├── CouponItem.vue │ │ │ ├── InputItem.vue │ │ │ ├── MineAvatar.vue │ │ │ ├── MineNavItem.vue │ │ │ └── taker │ │ │ │ └── Student.vue │ │ ├── order │ │ │ ├── AddressText.vue │ │ │ ├── DetailInfo.vue │ │ │ ├── MchBar.vue │ │ │ ├── OrderItem.vue │ │ │ ├── OrderTab.vue │ │ │ ├── TakerBar.vue │ │ │ ├── TakerOpt.vue │ │ │ └── UserOpt.vue │ │ ├── publish │ │ │ ├── CouponBtn.vue │ │ │ ├── DatePicker.vue │ │ │ ├── PubInfo.vue │ │ │ └── PublishBtn.vue │ │ └── service │ │ │ ├── ServiceBar.vue │ │ │ ├── ServiceBtn.vue │ │ │ ├── ServiceItem.vue │ │ │ ├── ServiceTab.vue │ │ │ ├── TitleBar.vue │ │ │ ├── clear │ │ │ ├── ClearInfo.vue │ │ │ └── ClearItem.vue │ │ │ ├── components │ │ │ ├── AddressBar.vue │ │ │ ├── AddressBarSingle.vue │ │ │ ├── AddressText.vue │ │ │ ├── Annex.vue │ │ │ ├── Desc.vue │ │ │ ├── Dot.vue │ │ │ ├── InputNumber.vue │ │ │ ├── LabelInput.vue │ │ │ ├── NextBtn.vue │ │ │ ├── ServiceRadio.vue │ │ │ └── Tabs.vue │ │ │ ├── errands │ │ │ ├── ErrandsInfo.vue │ │ │ └── WeightPicker.vue │ │ │ ├── express │ │ │ ├── ExpressInfo.vue │ │ │ └── ExpressItem.vue │ │ │ ├── move │ │ │ ├── MoveInfo.vue │ │ │ └── MoveItem.vue │ │ │ ├── play │ │ │ └── PlayInfo.vue │ │ │ └── software │ │ │ └── SoftwareInfo.vue │ ├── main.ts │ ├── manifest.json │ ├── mixins │ │ └── service-mixin.vue │ ├── pages.json │ ├── pages │ │ ├── index │ │ │ └── index.vue │ │ ├── login │ │ │ ├── login.vue │ │ │ └── phone │ │ │ │ └── phone.vue │ │ ├── mine │ │ │ ├── address │ │ │ │ ├── address.vue │ │ │ │ └── edit.vue │ │ │ ├── mine.vue │ │ │ ├── taker │ │ │ │ ├── bank │ │ │ │ │ ├── bank.vue │ │ │ │ │ └── edit.vue │ │ │ │ ├── cash │ │ │ │ │ ├── cash.vue │ │ │ │ │ └── record.vue │ │ │ │ ├── charge.vue │ │ │ │ ├── register.vue │ │ │ │ ├── status.vue │ │ │ │ └── taker.vue │ │ │ └── update.vue │ │ ├── order │ │ │ ├── cancel.vue │ │ │ ├── detail.vue │ │ │ └── order.vue │ │ ├── publish │ │ │ └── publish.vue │ │ ├── service │ │ │ ├── errands │ │ │ │ └── errands.vue │ │ │ ├── express │ │ │ │ └── express.vue │ │ │ ├── play │ │ │ │ └── play.vue │ │ │ └── software │ │ │ │ └── software.vue │ │ └── text │ │ │ └── text.vue │ ├── sfc.d.ts │ ├── static │ │ ├── avatar-card.png │ │ ├── bus.jpg │ │ ├── card-exam.jpeg │ │ ├── coupon-none.png │ │ ├── cri_right.png │ │ ├── default.png │ │ ├── edit.png │ │ ├── empty.png │ │ ├── home-def.png │ │ ├── home.png │ │ ├── lines.png │ │ ├── mine-def.png │ │ ├── mine.png │ │ ├── name.png │ │ ├── national-card.png │ │ ├── order-none.png │ │ ├── order.png │ │ ├── order_def.png │ │ ├── phone.png │ │ ├── print-excel.png │ │ ├── print-pdf.png │ │ ├── print-ppt.png │ │ ├── print-word.png │ │ ├── search-none.png │ │ └── shop-none.png │ ├── store │ │ ├── index.ts │ │ └── modules │ │ │ ├── config.ts │ │ │ ├── coupon.ts │ │ │ ├── profile.ts │ │ │ ├── publish.ts │ │ │ ├── school.ts │ │ │ └── shop.ts │ ├── uni.scss │ └── utils │ │ ├── api.ts │ │ ├── common.ts │ │ ├── constrants.ts │ │ ├── constrants.ts.bak │ │ ├── pay.ts │ │ └── request.ts └── tsconfig.json └── server ├── .editorconfig ├── .eslintrc.json ├── .gitignore ├── .prettierrc.js ├── apidoc.json ├── bootstrap.js ├── ecosystem.config.js ├── jest.config.js ├── jest.setup.js ├── package.json ├── src ├── cert │ └── readme.md ├── config │ ├── config.default.ts │ ├── config.env.ts.bak │ └── plugin.ts ├── configuration.ts ├── constant.ts ├── controller │ ├── admin │ │ ├── admin.controller.ts │ │ ├── cash.controller.ts │ │ ├── config.controller.ts │ │ ├── file.controller.ts │ │ ├── map.controller.ts │ │ ├── richtext.controller.ts │ │ ├── school.controller.ts │ │ ├── schoolAnalysis.controller.ts │ │ ├── schoolArea.controller.ts │ │ ├── schoolOrder.controller.ts │ │ ├── sts.controller.ts │ │ ├── taker.controller.ts │ │ ├── user.controller.ts │ │ ├── wxAnalysis.controller.ts │ │ ├── wxSubscribeMessage.controller.ts │ │ └── wxapp.controller.ts │ ├── api │ │ ├── bank.controller.ts │ │ ├── baseapp │ │ │ ├── address.controler.ts │ │ │ ├── cash.controller.ts │ │ │ ├── config.controller.ts │ │ │ ├── order.controller.ts │ │ │ ├── publish.controller.ts │ │ │ ├── richtext.controller.ts │ │ │ ├── school.controller.ts │ │ │ ├── taker.controller.ts │ │ │ └── takerAnalysis.controller.ts │ │ ├── index.ts │ │ ├── map.controller.ts │ │ ├── server.controller.ts │ │ ├── sms.controller.ts │ │ ├── upload.controller.ts │ │ ├── user.controller.ts │ │ └── wxapp.controller.ts │ └── base.controller.ts ├── dto │ ├── address.dto.ts │ ├── admin.dto.ts │ ├── analysis.dto.ts │ ├── bank.dto.ts │ ├── cash.dto.ts │ ├── common.dto.ts │ ├── config.dto.ts │ ├── coupon.dto.ts │ ├── errands.dto.ts │ ├── file.dto.ts │ ├── map.dto.ts │ ├── order.dto.ts │ ├── orderSchool.dto.ts │ ├── publish.dto.ts │ ├── richtext.dto.ts │ ├── rider.dto.ts │ ├── school.dto.ts │ ├── taker.dto.ts │ ├── user.dto.ts │ ├── wx.dto.ts │ └── wxapp.dto.ts ├── entity │ ├── Base.ts │ ├── admin.entity.ts │ ├── banks.entity.ts │ ├── cash.entity.ts │ ├── config.entity.ts │ ├── errandsTmplate.entity.ts │ ├── fileGroup.entity.ts │ ├── files.entity.ts │ ├── richtext.entity.ts │ ├── school.entity.ts │ ├── schoolArea.entity.ts │ ├── schoolBalanceSheet.entity.ts │ ├── schoolBuilding.entity.ts │ ├── schoolCarousels.entity.ts │ ├── schoolOrders.entity.ts │ ├── taker.entity.ts │ ├── user.entity.ts │ ├── userCoupon.entity.ts │ ├── userSchoolAddress.entity.ts │ └── wxapp.entity.ts ├── error │ ├── config.error.ts │ ├── default.error.ts │ ├── login.error.ts │ ├── notice.error.ts │ ├── setpwd.error.ts │ └── taker.error.ts ├── filter │ └── all.filter.ts ├── interface.ts ├── middleware │ ├── admin.middleware.ts │ ├── app.middleware.ts │ └── user.middleware.ts ├── service │ ├── admin.service.ts │ ├── ali │ │ ├── oss.service.ts │ │ ├── sms.service.ts │ │ └── sts.service.ts │ ├── anlysis.service.ts │ ├── base.service.ts │ ├── cash.service.ts │ ├── config.service.ts │ ├── http.service.ts │ ├── jwt.service.ts │ ├── map.service.ts │ ├── order.service.ts │ ├── publish.service.ts │ ├── query.service.ts │ ├── redis.service.ts │ ├── school.service.ts │ ├── schoolBalanceSheet.service.ts │ ├── schoolOrders.service.ts │ ├── subscribeService.ts │ ├── taker.service.ts │ ├── tool.service.ts │ ├── user.service.ts │ ├── wx.service.ts │ ├── wx │ │ └── subscribeMessage.service.ts │ └── wxapp.service.ts ├── task │ └── schoolOrder.task.ts └── utils │ └── common.ts ├── test └── controller │ ├── api.test.ts │ └── home.test.ts ├── tsconfig.json └── typings ├── app └── index.d.ts └── config ├── index.d.ts └── plugin.d.ts /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | package-lock.json 3 | yarn.lock -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 landalfyao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 校园跑腿-跑腿便利店小程序 2 | 3 | - 本项目持续维护,如有问题请加 **QQ 群:206984955**, QQ:714834195 4 | - 如果对您有帮助,您可以点右上角 "Star" 支持一下 谢谢! 5 | 6 | ## 项目介绍 7 | 8 | 本项目后端采用 midway3.0,后台采用 nuxt2.x,小程序采用 uniapp 实现的一套跑腿下单接单系统。 9 | 10 | #### 主要功能 11 | 12 | 跑腿、快递代取、陪练陪玩、软件安装、申请接单、用户下单、提现、物品重量计算等。 13 | 14 | ## 体验或交流 15 | 16 |  17 | 18 | ## 开始开发 19 | 20 | - [查看开发文档](https://gitee.com/landalfyao/ddapp/blob/master/DEV.md) 21 | - [配置参考](https://gitee.com/landalfyao/ddrun/wikis/pages?sort_id=5937464&doc_id=403865) 22 | - [部署教程](https://gitee.com/landalfyao/ddapp/wikis/pages) 23 | 24 | ## 小程序页面 25 | 26 |  27 | 28 | ## 后台页面 29 | 30 |  31 |  32 |  33 |  34 | -------------------------------------------------------------------------------- /admin/.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /admin/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true 6 | }, 7 | extends: ['@nuxtjs/eslint-config-typescript', 'plugin:nuxt/recommended', 'prettier'], 8 | plugins: [], 9 | // add your custom rules here 10 | rules: { 11 | camelcase: 'off', 12 | '@typescript-eslint/camelcase': 0 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /admin/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Node template 3 | # Logs 4 | /logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (https://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # TypeScript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | 62 | # parcel-bundler cache (https://parceljs.org/) 63 | .cache 64 | 65 | # next.js build output 66 | .next 67 | 68 | # nuxt.js build output 69 | .nuxt 70 | 71 | # Nuxt generate 72 | dist 73 | 74 | # vuepress build output 75 | .vuepress/dist 76 | 77 | # Serverless directories 78 | .serverless 79 | 80 | # IDE / Editor 81 | .idea 82 | 83 | # Service worker 84 | sw.* 85 | 86 | # macOS 87 | .DS_Store 88 | 89 | # Vim swap files 90 | *.swp 91 | yarn.lock -------------------------------------------------------------------------------- /admin/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | jsxSingleQuote: true, 3 | disableLanguages: [], // 句尾添加分号 4 | arrowParens: 'avoid', // 箭头函数会自动判断 是否添加圆括号 5 | endOfLine: 'lf', // 采用lf 换行机制 6 | jsxBracketSameLine: false, // jsx换行时 尖括号放后面 7 | useTabs: false, // 是否采用tab是用来换行 8 | printWidth: 100, // 一行的字符数,如果超过会进行换行,默认为80 9 | semi: true, // 尾部是否具有分号 10 | singleQuote: true, // 是否使用单引号 11 | requireConfig: true, 12 | bracketSpacing: true, // 对象中是否使用空格 13 | tabWidth: 2, // tab缩进大小,默认为2 14 | useTabs: false, // 是否使用tab 作为缩进 15 | trailingComma: 'none' // 对象字面量结尾是否使用逗号 16 | }; 17 | -------------------------------------------------------------------------------- /admin/README.md: -------------------------------------------------------------------------------- 1 | # 后台管理系统 2 | 3 | ## 一、安装启动 4 | 5 | ``` 6 | # 安装 7 | yarn 8 | 9 | # 启动 并访问 本地服务器 localhost 10 | yarn local 11 | 12 | # 启动 并访问 线上服务器 13 | yarn prod 14 | ``` 15 | 16 | ## 二、开发规范 17 | 18 | ### 1.命名需遵从以下原则 19 | 20 | - 变量名驼峰规范 21 | - 常量首字母大写 22 | - 禁止缩写 详细一些 23 | - 数组一律 s 结尾 users buckets 24 | - 函数命名规范 动词开头 can get set load send handle filter fetch 25 | - 组件的文件夹为 小写字母+下划线 组件名为驼峰 首字母大写 26 | 27 | ### 2.框架 28 | 29 | - nuxt 30 | - ant-design 31 | - less 32 | - typescript 33 | - 使用 eslint 和 prettier .vscode 34 | - 使用 yarn 代替 npm 35 | 36 | ### 3.git 规范 37 | 38 | - 使用前缀 fix: bug fixed 39 | (注意,是英文的冒号,后面跟一个英文的空格) 40 | > feat: 新功能(feature) 41 | > fix: 修补 bug 42 | > docs: 文档(documentation) 43 | > style: 格式(不影响代码运行的变动) 44 | > refactor: 重构(即不是新增功能,也不是修改 bug 的代码变动) 45 | > test: 增加测试 46 | > chore: 构建过程或辅助工具的变动 47 | - 使用 pull request 48 | - 使用 dev 分支开发 49 | 50 | ### 4.全局组件 51 | 52 | - 注册到全局的组件一律写到 ~/components/base 目录下 53 | - 在~/components/base/index.js 中注册组件 54 | 55 | ### 5.文件创建规范 56 | 57 | - ~/pages 目录下创建页面文件夹+index.ts 58 | - 页面的所有组件编写在~/components 目录下,并以页面的文件夹命名 59 | - 公用混合方法文件写在~/plugins/mixins 目录下 60 | -------------------------------------------------------------------------------- /admin/assets/font/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/admin/assets/font/iconfont.ttf -------------------------------------------------------------------------------- /admin/assets/font/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/admin/assets/font/iconfont.woff -------------------------------------------------------------------------------- /admin/assets/font/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/admin/assets/font/iconfont.woff2 -------------------------------------------------------------------------------- /admin/assets/images/empty-design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/admin/assets/images/empty-design.png -------------------------------------------------------------------------------- /admin/assets/images/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/admin/assets/images/login.png -------------------------------------------------------------------------------- /admin/assets/images/sub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/admin/assets/images/sub.png -------------------------------------------------------------------------------- /admin/assets/style/theme.less: -------------------------------------------------------------------------------- 1 | @primary-color: #955ce6; // 全局主色 2 | @link-color: #955ce6; // 链接色 3 | @border-radius-base: 2px; 4 | @input-height-base: 40px; 5 | .fo-t { 6 | color: #955ce6; 7 | } 8 | -------------------------------------------------------------------------------- /admin/components/Logo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /admin/components/base/Color/ColorPicker.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 37 | 50 | -------------------------------------------------------------------------------- /admin/components/base/Date/DatePicker.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 按时间查询: 4 | 11 | 12 | 13 | 37 | -------------------------------------------------------------------------------- /admin/components/base/Divider/DividerV.vue: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 22 | 29 | -------------------------------------------------------------------------------- /admin/components/base/Empty/Empty.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 35 | 42 | -------------------------------------------------------------------------------- /admin/components/base/Picture/Picture.vue: -------------------------------------------------------------------------------- 1 | 2 | 7 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 61 | 69 | -------------------------------------------------------------------------------- /admin/components/base/Tag/Tag.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 25 | -------------------------------------------------------------------------------- /admin/components/base/UserLink/AdminLink.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /admin/components/base/UserLink/AgentLink.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /admin/components/base/UserLink/RiderLink.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /admin/components/base/UserLink/TakerLink.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /admin/components/base/UserLink/UserLink.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /admin/components/base/action/Action.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | e.preventDefault()"> 4 | 5 | 6 | 7 | 8 | 9 | 14 | {{ item.label }} 15 | 16 | 17 | 18 | 19 | 20 | 39 | -------------------------------------------------------------------------------- /admin/components/base/list/HoverList.vue: -------------------------------------------------------------------------------- 1 | 2 | 7 | {{ label }} 8 | 9 | 10 | 25 | 42 | -------------------------------------------------------------------------------- /admin/components/material/GroupEdit.vue: -------------------------------------------------------------------------------- 1 | 2 | 13 | 分组名称: 14 | 15 | 16 | 17 | 60 | 61 | -------------------------------------------------------------------------------- /admin/components/material/GroupMove.vue: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | {{ item.groupName }} 15 | 16 | 17 | 18 | 19 | 54 | 55 | -------------------------------------------------------------------------------- /admin/components/material/PicItem.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | {{ options.fileName }} 11 | 12 | 13 | 46 | 75 | -------------------------------------------------------------------------------- /admin/components/official/layout/Header.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{ systemName || title }} 8 | 9 | 10 | 11 | 开源校园版 12 | 13 | 14 | 15 | 16 | 38 | 58 | -------------------------------------------------------------------------------- /admin/components/official/layout/Main.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 20 | -------------------------------------------------------------------------------- /admin/components/official/login/StyleBtn.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ label }} 7 | 8 | 9 | 28 | 55 | -------------------------------------------------------------------------------- /admin/components/order/OrderHandleModal.vue: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 取消超过15分钟未付款订单 13 | 14 | 15 | 取消超过截止时间未接单订单 16 | 17 | 18 | 超过2小时未点击确认的订单自动完成 19 | 20 | 21 | 22 | 63 | 64 | -------------------------------------------------------------------------------- /admin/components/order/lib/ClearInfo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | {{ item.name }} 10 | 11 | x{{ item.count }} 12 | {{ item.price }}元/{{ item.unit }} 13 | 14 | 15 | 16 | 31 | -------------------------------------------------------------------------------- /admin/components/order/lib/ErrandsInfo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ item }} 6 | 7 | 8 | 9 | 10 | 重量: 11 | {{ priceDetails.weight }}kg 12 | 13 | 价格: {{ priceDetails.weightPriceTotal }}元 14 | 15 | 16 | 17 | {{ item }} 18 | 19 | 20 | 21 | 22 | 23 | 31 | 32 | 33 | 34 | 51 | -------------------------------------------------------------------------------- /admin/components/order/lib/ExpressInfo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 快递件选项: 5 | {{ order.priceDetails.expressObj.name }} 6 | 7 | 价格: {{ order.priceDetails.expressObj.price }}元 8 | 9 | 10 | 25 | -------------------------------------------------------------------------------- /admin/components/order/lib/MoveInfo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 载具: {{ order.priceDetails.vehicleName }} 5 | 价格: {{ order.priceDetails.vehiclePrice }}元 6 | 7 | 8 | 是否需要帮助: {{ order.priceDetails.needsHelp ? '是' : '否' }} 9 | 10 | 价格: {{ order.priceDetails.helpPrice }}元 11 | 12 | 13 | 14 | 15 | 30 | -------------------------------------------------------------------------------- /admin/components/order/lib/PlayInfo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ order.priceDetails.desc }} 4 | 5 | 6 | 21 | -------------------------------------------------------------------------------- /admin/components/order/lib/PrintInfo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 文件数量: 6 | {{ order.priceDetails.files.length }} 个 7 | 8 | 重量: {{ order.priceDetails.totalWeight }}kg 9 | 10 | 11 | 12 | 一份页数: 13 | {{ order.priceDetails.pageSize }} 页 14 | 15 | 打印份数: {{ order.priceDetails.copySize }}份 16 | 17 | 18 | 纸张单价: {{ order.priceDetails.unitPaperPrice }}元 19 | 纸张优惠: {{ order.priceDetails.paperRuleDiscountAmount }}元 20 | 21 | 22 | 纸张原价: {{ order.priceDetails.originPrice }}元 23 | 24 | 28 | {{ order.priceDetails.paperRuleDiscountText }}元 29 | 30 | 34 | 35 | 36 | 55 | -------------------------------------------------------------------------------- /admin/components/order/lib/RepairInfo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 维修项目: 5 | {{ order.priceDetails.repairName }} 6 | 7 | 价格: {{ order.priceDetails.repairPrice }}元 8 | 9 | 10 | 25 | -------------------------------------------------------------------------------- /admin/components/rider/Receive.vue: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 60 | -------------------------------------------------------------------------------- /admin/components/rider/Refuse.vue: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 55 | -------------------------------------------------------------------------------- /admin/components/rider/RefuseCash.vue: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 55 | -------------------------------------------------------------------------------- /admin/components/school/AreaEditModal.vue: -------------------------------------------------------------------------------- 1 | 2 | 12 | 区域名称: 13 | 14 | 15 | 是否显示: 16 | 17 | 显示 18 | 关闭 19 | 20 | 21 | 22 | 67 | 68 | -------------------------------------------------------------------------------- /admin/components/service/ServiceItem.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ options.label }} 7 | 8 | 9 | 26 | 46 | -------------------------------------------------------------------------------- /admin/components/service/components/ClearEditModal.vue: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 27 | 28 | 29 | 30 | 31 | 66 | 67 | -------------------------------------------------------------------------------- /admin/components/service/components/ErrandsModal.vue: -------------------------------------------------------------------------------- 1 | 2 | 11 | 选择跑腿项: 刷新数据 12 | 13 | {{ item.templateName }}({{ item.showName }}) 16 | 17 | 18 | 没有找到跑腿项点此添加 21 | 22 | 23 | 24 | 62 | 63 | -------------------------------------------------------------------------------- /admin/components/service/components/ExpressEditModel.vue: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 25 | 26 | 27 | 28 | 62 | 63 | -------------------------------------------------------------------------------- /admin/components/service/lib/Play.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 18 | 19 | 提示:输入一项按回车 20 | 21 | 22 | 23 | 46 | -------------------------------------------------------------------------------- /admin/components/service/lib/Software.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 18 | 19 | 提示:输入一项按回车 20 | 21 | 22 | 23 | 46 | -------------------------------------------------------------------------------- /admin/components/taker/Receive.vue: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 54 | -------------------------------------------------------------------------------- /admin/components/taker/Refuse.vue: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 55 | -------------------------------------------------------------------------------- /admin/components/user/RealnameModal.vue: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 取消 13 | 确认修改 14 | 15 | 16 | 17 | 51 | -------------------------------------------------------------------------------- /admin/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | title: '码里码外后台管理系统', 3 | localDomain: 'http://localhost:8001', 4 | envDomain: 'http://xx.xxx.cn', 5 | prodDomain: 'https://op.xxx.cn', 6 | port: 8888, 7 | copyright: 'Copyright © 2022 码里码外 All right reserved.', 8 | copyrightContent: '由杭州码里码外网络科技提供技术支持' 9 | }; 10 | -------------------------------------------------------------------------------- /admin/content/hello.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Getting started 3 | description: 'Empower your NuxtJS application with @nuxt/content module: write in a content/ directory and fetch your Markdown, JSON, YAML and CSV files through a MongoDB like API, acting as a Git-based Headless CMS.' 4 | --- 5 | 6 | Empower your NuxtJS application with `@nuxtjs/content` module: write in a `content/` directory and fetch your Markdown, JSON, YAML and CSV files through a MongoDB like API, acting as a **Git-based Headless CMS**. 7 | 8 | ## Writing content 9 | 10 | Learn how to write your `content/`, supporting Markdown, YAML, CSV and JSON: https://content.nuxtjs.org/writing. 11 | 12 | ## Fetching content 13 | 14 | Learn how to fetch your content with `$content`: https://content.nuxtjs.org/fetching. 15 | 16 | ## Displaying content 17 | 18 | Learn how to display your Markdown content with the `` component directly in your template: https://content.nuxtjs.org/displaying. -------------------------------------------------------------------------------- /admin/content/help/shortcut-key.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 快捷键 3 | --- 4 | -------------------------------------------------------------------------------- /admin/layouts/choose.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 27 | 46 | -------------------------------------------------------------------------------- /admin/layouts/global.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 37 | 46 | -------------------------------------------------------------------------------- /admin/pages/config/agreementRider.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 骑手协议 4 | 5 | 提交保存 14 | 15 | 16 | 48 | -------------------------------------------------------------------------------- /admin/pages/config/app.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 小程序设置 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 29 | -------------------------------------------------------------------------------- /admin/pages/config/cash.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 开启 9 | 关闭 10 | 11 | 12 | 13 | 14 | 提交保存 17 | 18 | 19 | 20 | 21 | 22 | 52 | -------------------------------------------------------------------------------- /admin/pages/config/mapupload.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 地图及上传设置 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 31 | -------------------------------------------------------------------------------- /admin/pages/config/subscribe.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 订阅消息设置 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 21 | -------------------------------------------------------------------------------- /admin/pages/config/user.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 用户指南 4 | 5 | 提交保存 14 | 15 | 16 | 48 | -------------------------------------------------------------------------------- /admin/pages/config/wxsubscribe.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 订阅消息设置 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 36 | -------------------------------------------------------------------------------- /admin/pages/index.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 数据总览 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 34 | -------------------------------------------------------------------------------- /admin/pages/school/page.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ item.style.navigationBarTitleText || '小程序页面' }} 6 | /{{ item.path }} 7 | 8 | 9 | 10 | 11 | 22 | -------------------------------------------------------------------------------- /admin/plugins/antd-ui.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Antd from 'ant-design-vue/lib'; 3 | import scrollbar from 'vue-scrollbar-live'; 4 | 5 | Vue.use(Antd); 6 | Vue.component('Scrollbar', scrollbar); 7 | Vue.prototype.$message.config({ 8 | maxCount: 1 9 | }); 10 | -------------------------------------------------------------------------------- /admin/plugins/bus.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | const bus = {} as any; 4 | 5 | bus.install = function () { 6 | Vue.prototype.$bus = new Vue(); 7 | }; 8 | 9 | Vue.use(bus); 10 | -------------------------------------------------------------------------------- /admin/plugins/froala.js: -------------------------------------------------------------------------------- 1 | import 'froala-editor/css/froala_editor.pkgd.min.css'; 2 | import 'froala-editor/js/languages/zh_cn'; 3 | import 'froala-editor/js/plugins/align.min.js'; 4 | import 'froala-editor/js/plugins/quick_insert.min.js'; 5 | import 'froala-editor/js/plugins/fullscreen.min.js'; 6 | import 'froala-editor/js/plugins/table.min.js'; 7 | import 'froala-editor/js/plugins/table.min.js'; 8 | import 'froala-editor/js/plugins/url.min.js'; 9 | import 'froala-editor/js/plugins/link.min.js'; 10 | import 'froala-editor/js/plugins/word_paste.min.js'; 11 | import 'froala-editor/js/plugins/lists.min.js'; 12 | import 'froala-editor/js/plugins/line_height.min.js'; 13 | import 'froala-editor/js/plugins/line_breaker.min.js'; 14 | import 'froala-editor/js/plugins/inline_style.min.js'; 15 | import 'froala-editor/js/plugins/font_size.min.js'; 16 | import 'froala-editor/js/plugins/font_family.min'; 17 | import 'froala-editor/js/plugins/colors.min.js'; 18 | import 'froala-editor/js/plugins/draggable.min'; 19 | import 'froala-editor/js/plugins/code_view.min'; 20 | import 'froala-editor/js/plugins/code_beautifier.min'; 21 | import 'froala-editor/js/plugins/edit_in_popup.min'; 22 | import 'froala-editor/js/plugins/entities.min'; 23 | import 'froala-editor/js/plugins/char_counter.min'; 24 | import 'froala-editor/js/plugins/paragraph_format.min'; 25 | import 'froala-editor/js/plugins/paragraph_style.min'; 26 | import 'froala-editor/js/plugins/print.min'; 27 | import 'froala-editor/js/plugins/forms.min'; 28 | import 'froala-editor/js/plugins/image.min'; 29 | import 'froala-editor/js/plugins/video.min'; 30 | import 'froala-editor/js/plugins/file.min.js'; 31 | -------------------------------------------------------------------------------- /admin/plugins/mixins/edit-mixin.vue: -------------------------------------------------------------------------------- 1 | 56 | -------------------------------------------------------------------------------- /admin/plugins/mixins/modal-mixin.vue: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /admin/plugins/mixins/service-mixin.vue: -------------------------------------------------------------------------------- 1 | 27 | 37 | -------------------------------------------------------------------------------- /admin/plugins/mixins/table-data-mixin.vue: -------------------------------------------------------------------------------- 1 | 56 | -------------------------------------------------------------------------------- /admin/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/admin/static/favicon.ico -------------------------------------------------------------------------------- /admin/store/README.md: -------------------------------------------------------------------------------- 1 | # STORE 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your Vuex Store files. 6 | Vuex Store option is implemented in the Nuxt.js framework. 7 | 8 | Creating a file in this directory automatically activates the option in the framework. 9 | 10 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/vuex-store). 11 | -------------------------------------------------------------------------------- /admin/store/index.ts: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex'; 2 | import Vue from 'vue'; 3 | import profile from './modules/profile'; 4 | import subscribe from './modules/subscribe'; 5 | import file from './modules/file'; 6 | import system from './modules/system'; 7 | import { VersionType } from './version'; 8 | Vue.use(Vuex); 9 | interface IndexState { 10 | tempData: any; 11 | beginDate: string; 12 | endDate: string; 13 | version: 'city' | 'school' | 'community' | ''; 14 | versionType: string; 15 | isSass: Boolean; 16 | } 17 | export default () => { 18 | // eslint-disable-next-line import/no-named-as-default-member 19 | return new Vuex.Store({ 20 | state: { 21 | tempData: null as any, 22 | beginDate: '', 23 | endDate: '', 24 | version: '', 25 | versionType: VersionType 26 | } as IndexState, 27 | mutations: { 28 | setVersionType(state: IndexState, val: string) { 29 | state.versionType = val; 30 | }, 31 | setTempData(state: IndexState, val: any) { 32 | state.tempData = val; 33 | }, 34 | setBeginDate(state: IndexState, val) { 35 | state.beginDate = val; 36 | }, 37 | setEndDate(state: IndexState, val) { 38 | state.endDate = val; 39 | }, 40 | setVersion(state: IndexState, val) { 41 | state.version = val; 42 | localStorage.setItem('versionName', val); 43 | } 44 | }, 45 | actions: {}, 46 | modules: { 47 | profile, 48 | subscribe, 49 | file, 50 | system 51 | } 52 | }); 53 | }; 54 | -------------------------------------------------------------------------------- /admin/store/modules/profile.ts: -------------------------------------------------------------------------------- 1 | import api from '~/plugins/api'; 2 | interface State { 3 | adminNo: string; 4 | realName: string; 5 | mobileNumber: string; 6 | adminName: string; 7 | avatarUrl: string; 8 | } 9 | 10 | export default { 11 | namespaced: true, 12 | state: { 13 | adminNo: '', 14 | realName: '', 15 | mobileNumber: '', 16 | adminName: '', 17 | avatarUrl: '' 18 | } as State, 19 | mutations: { 20 | setAdminInfo(state: State, data: any) { 21 | state.adminNo = data.adminNo; 22 | state.realName = data.realName; 23 | state.mobileNumber = data.mobileNumber; 24 | state.adminName = data.adminName; 25 | state.avatarUrl = data.avatarUrl; 26 | }, 27 | 28 | clearAdminInfo(state: State) { 29 | state.adminNo = ''; 30 | state.realName = ''; 31 | state.mobileNumber = ''; 32 | state.adminName = ''; 33 | state.avatarUrl = ''; 34 | }, 35 | 36 | setAdminNo(state: State, val: string) { 37 | state.adminNo = val; 38 | } 39 | }, 40 | actions: { 41 | async fetchUserInfo({ commit }: { commit: Function }) { 42 | const res = (await api.adminInfo()) as any; 43 | if (res.code === 200) { 44 | commit('setAdminInfo', res.data); 45 | } 46 | } 47 | } 48 | }; 49 | -------------------------------------------------------------------------------- /admin/store/modules/subscribe.ts: -------------------------------------------------------------------------------- 1 | import api from '~/plugins/api'; 2 | interface Subscribe { 3 | categoryId: string; 4 | tid: number; 5 | title: string; 6 | type: number; 7 | } 8 | interface State { 9 | mySubscribes: Subscribe[]; 10 | } 11 | 12 | export default { 13 | namespaced: true, 14 | state: { 15 | mySubscribes: [] 16 | } as State, 17 | mutations: { 18 | setMySubscribes(state: State, val: Subscribe[]) { 19 | state.mySubscribes = val; 20 | } 21 | }, 22 | actions: { 23 | async fetchMySubscribe({ commit }: { commit: Function }) { 24 | const res = (await api.wxSubscribeTemplates()) as any; 25 | if (res.code === 200) { 26 | commit('setMySubscribes', res.data); 27 | } 28 | } 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /admin/store/modules/system.ts: -------------------------------------------------------------------------------- 1 | import api from '~/plugins/api'; 2 | interface State { 3 | systemName: string; 4 | agentSystemName: string; 5 | companyName: string; 6 | recordNo: string; 7 | logo: string; 8 | 9 | // 是否有插件 10 | hasPlugin: boolean; 11 | activity: boolean; 12 | bulletinBoard: boolean; 13 | shop: boolean; 14 | } 15 | 16 | export default { 17 | namespaced: true, 18 | state: { 19 | systemName: '', 20 | agentSystemName: '', 21 | companyName: '', 22 | recordNo: '', 23 | logo: '' 24 | } as State, 25 | mutations: { 26 | setSystemInfo(state: State, data: any) { 27 | state.systemName = data.systemName; 28 | state.agentSystemName = data.agentSystemName; 29 | state.companyName = data.companyName; 30 | state.recordNo = data.recordNo; 31 | state.logo = data.logo; 32 | } 33 | }, 34 | actions: { 35 | async fetchSystemInfo({ commit }: { commit: Function }) { 36 | const res = (await api.adminSystemInfo()) as any; 37 | if (res.code === 200 && res.data) { 38 | commit('setSystemInfo', res.data); 39 | if (res.data.systemName) { 40 | document.title = res.data.systemName; 41 | } 42 | } 43 | } 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /admin/store/version.ts: -------------------------------------------------------------------------------- 1 | export const VersionType = 'all'; 2 | -------------------------------------------------------------------------------- /admin/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "lib": [ 7 | "ESNext", 8 | "ESNext.AsyncIterable", 9 | "DOM" 10 | ], 11 | "esModuleInterop": true, 12 | "allowJs": true, 13 | "sourceMap": true, 14 | "strict": true, 15 | "noEmit": true, 16 | "experimentalDecorators": true, 17 | "baseUrl": ".", 18 | "paths": { 19 | "~/*": [ 20 | "./*" 21 | ], 22 | "@/*": [ 23 | "./*" 24 | ] 25 | }, 26 | "types": [ 27 | "@nuxt/types", 28 | "@nuxtjs/axios", 29 | "@nuxt/content", 30 | "@types/node" 31 | ] 32 | }, 33 | "exclude": [ 34 | "node_modules", 35 | ".nuxt", 36 | "dist" 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /admin/vue-shim.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@tween/tweenjs'; 2 | declare module 'vue-color'; 3 | declare module 'froala-editor'; 4 | -------------------------------------------------------------------------------- /miniprogram/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | unpackage/ 4 | dist/ 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | 15 | # Editor directories and files 16 | .project 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw* 24 | 25 | yarn.lock 26 | -------------------------------------------------------------------------------- /miniprogram/README.md: -------------------------------------------------------------------------------- 1 | # 跑腿便利店小程序 2 | 3 | ## 安装 4 | 5 | ``` 6 | yarn 7 | ``` 8 | 9 | ### 启动 10 | 11 | ``` 12 | # 启动为微信小程序 13 | yarn dev-wx 14 | 15 | # 启动为支付宝小程序 16 | yarn dev-ali 17 | ``` 18 | 19 | ### 构建 20 | 21 | ``` 22 | # 构建为微信小程序 23 | yarn build-wx 24 | 25 | # 构建为支付宝小程序 26 | yarn build-ali 27 | ``` 28 | 29 | ### 官方文档 30 | 31 | [https://zh.uniapp.dcloud.io/](https://zh.uniapp.dcloud.io/). 32 | -------------------------------------------------------------------------------- /miniprogram/babel.config.js: -------------------------------------------------------------------------------- 1 | const plugins = [] 2 | 3 | if (process.env.UNI_OPT_TREESHAKINGNG) { 4 | plugins.push(require('@dcloudio/vue-cli-plugin-uni-optimize/packages/babel-plugin-uni-api/index.js')) 5 | } 6 | 7 | if ( 8 | ( 9 | process.env.UNI_PLATFORM === 'app-plus' && 10 | process.env.UNI_USING_V8 11 | ) || 12 | ( 13 | process.env.UNI_PLATFORM === 'h5' && 14 | process.env.UNI_H5_BROWSER === 'builtin' 15 | ) 16 | ) { 17 | const path = require('path') 18 | 19 | const isWin = /^win/.test(process.platform) 20 | 21 | const normalizePath = path => (isWin ? path.replace(/\\/g, '/') : path) 22 | 23 | const input = normalizePath(process.env.UNI_INPUT_DIR) 24 | try { 25 | plugins.push([ 26 | require('@dcloudio/vue-cli-plugin-hbuilderx/packages/babel-plugin-console'), 27 | { 28 | file (file) { 29 | file = normalizePath(file) 30 | if (file.indexOf(input) === 0) { 31 | return path.relative(input, file) 32 | } 33 | return false 34 | } 35 | } 36 | ]) 37 | } catch (e) {} 38 | } 39 | 40 | process.UNI_LIBRARIES = process.UNI_LIBRARIES || ['@dcloudio/uni-ui'] 41 | process.UNI_LIBRARIES.forEach(libraryName => { 42 | plugins.push([ 43 | 'import', 44 | { 45 | 'libraryName': libraryName, 46 | 'customName': (name) => { 47 | return `${libraryName}/lib/${name}/${name}` 48 | } 49 | } 50 | ]) 51 | }) 52 | module.exports = { 53 | presets: [ 54 | [ 55 | '@vue/app', 56 | { 57 | modules: 'commonjs', 58 | useBuiltIns: process.env.UNI_PLATFORM === 'h5' ? 'usage' : 'entry' 59 | } 60 | ] 61 | ], 62 | plugins 63 | } 64 | -------------------------------------------------------------------------------- /miniprogram/postcss.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | module.exports = { 3 | parser: require('postcss-comment'), 4 | plugins: [ 5 | require('postcss-import')({ 6 | resolve (id, basedir, importOptions) { 7 | if (id.startsWith('~@/')) { 8 | return path.resolve(process.env.UNI_INPUT_DIR, id.substr(3)) 9 | } else if (id.startsWith('@/')) { 10 | return path.resolve(process.env.UNI_INPUT_DIR, id.substr(2)) 11 | } else if (id.startsWith('/') && !id.startsWith('//')) { 12 | return path.resolve(process.env.UNI_INPUT_DIR, id.substr(1)) 13 | } 14 | return id 15 | } 16 | }), 17 | require('autoprefixer')({ 18 | remove: process.env.UNI_PLATFORM !== 'h5' 19 | }), 20 | require('@dcloudio/vue-cli-plugin-uni/packages/postcss') 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /miniprogram/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 14 | 15 | 16 | 17 | 18 | 19 | Please enable JavaScript to continue. 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /miniprogram/src/App.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 49 | -------------------------------------------------------------------------------- /miniprogram/src/assets/font/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/assets/font/iconfont.ttf -------------------------------------------------------------------------------- /miniprogram/src/assets/font/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/assets/font/iconfont.woff -------------------------------------------------------------------------------- /miniprogram/src/assets/font/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/assets/font/iconfont.woff2 -------------------------------------------------------------------------------- /miniprogram/src/assets/images/empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/assets/images/empty.png -------------------------------------------------------------------------------- /miniprogram/src/assets/style/service.scss: -------------------------------------------------------------------------------- 1 | .service-content { 2 | padding: 0 60rpx; 3 | } 4 | .service-main { 5 | border-radius: 40rpx 40rpx 0 0; 6 | background-color: #ffffff; 7 | padding: 0 30rpx; 8 | } 9 | -------------------------------------------------------------------------------- /miniprogram/src/components/base/empty/Empty.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 16 | 22 | 28 | 34 | 35 | 36 | 37 | 38 | 49 | 59 | -------------------------------------------------------------------------------- /miniprogram/src/components/base/image/image.vue: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 47 | -------------------------------------------------------------------------------- /miniprogram/src/components/base/scroll/ScrollX.vue: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 28 | 34 | -------------------------------------------------------------------------------- /miniprogram/src/components/base/watermark/Watermark.vue: -------------------------------------------------------------------------------- 1 | 2 | 由码里码外团队提供技术支持 3 | -------------------------------------------------------------------------------- /miniprogram/src/components/location/LocationBar.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {{ schoolName || "" }} 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 33 | 34 | 61 | -------------------------------------------------------------------------------- /miniprogram/src/components/location/searchBar.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 搜索 20 | 21 | 22 | 23 | 24 | 48 | 69 | -------------------------------------------------------------------------------- /miniprogram/src/components/mine/AddressChooseLocation.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 选择地址 6 | 7 | 8 | {{ label }} 9 | 请选择地点 10 | 11 | 12 | 13 | 14 | 48 | -------------------------------------------------------------------------------- /miniprogram/src/components/mine/AddressDetault.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 默认地址 10 | 11 | 12 | 13 | 14 | 25 | -------------------------------------------------------------------------------- /miniprogram/src/components/mine/AddressTab.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 校园地址 8 | 校外地址 13 | 14 | 15 | 26 | 48 | -------------------------------------------------------------------------------- /miniprogram/src/components/mine/MineNavItem.vue: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | {{ label }} 10 | 11 | 12 | 13 | 14 | 37 | 45 | -------------------------------------------------------------------------------- /miniprogram/src/components/order/AddressText.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ options.schoolBuild.area }}-{{ options.schoolBuild.build }}-{{ 6 | options.schoolBuild.detail 7 | }} 9 | 10 | 11 | 36 | 37 | -------------------------------------------------------------------------------- /miniprogram/src/components/order/DetailInfo.vue: -------------------------------------------------------------------------------- 1 | 2 | 6 | {{ label }} 7 | 8 | {{ value }} 9 | 10 | 11 | 12 | 13 | 40 | -------------------------------------------------------------------------------- /miniprogram/src/components/publish/CouponBtn.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 优惠券 6 | 7 | 8 | 暂无可用优惠券 9 | 有 {{ count }} 张优惠券可用 12 | 13 | {{ label }} 优惠{{ discount }}元 14 | 15 | 16 | 17 | 18 | 19 | 49 | -------------------------------------------------------------------------------- /miniprogram/src/components/publish/PubInfo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ label }} 5 | 6 | {{ value }} 7 | 16 | 17 | 18 | 19 | {{ 20 | item 21 | }} 22 | 23 | 24 | 25 | 49 | -------------------------------------------------------------------------------- /miniprogram/src/components/publish/PublishBtn.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 需支付 6 | {{ price }}元 7 | 8 | 付款并发布 11 | 12 | 13 | 14 | 15 | 26 | 39 | -------------------------------------------------------------------------------- /miniprogram/src/components/service/ServiceBtn.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {}" 11 | > 12 | 13 | 14 | 15 | 16 | 36 | 74 | -------------------------------------------------------------------------------- /miniprogram/src/components/service/TitleBar.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ title }} 5 | 6 | 7 | 26 | 37 | -------------------------------------------------------------------------------- /miniprogram/src/components/service/clear/ClearInfo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | {{ item.name }} 10 | 11 | x{{ item.count }} 12 | {{ item.price }}元/{{ item.unit }} 15 | 16 | 17 | 18 | 19 | 20 | 41 | -------------------------------------------------------------------------------- /miniprogram/src/components/service/clear/ClearItem.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ options.name }} 6 | {{ options.price }} 8 | 元/{{ options.unit }} 10 | 11 | {{ options.desc }} 12 | 13 | 18 | 19 | 20 | 43 | 52 | -------------------------------------------------------------------------------- /miniprogram/src/components/service/components/AddressText.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ options.mobileNumber }},{{ options.contactName }} 6 | {{ options.schoolBuild.area }}-{{ options.schoolBuild.build }}-{{ 8 | options.schoolBuild.detail 9 | }} 11 | 12 | 13 | 31 | -------------------------------------------------------------------------------- /miniprogram/src/components/service/components/Dot.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 43 | -------------------------------------------------------------------------------- /miniprogram/src/components/service/components/LabelInput.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ label }} 6 | 7 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /miniprogram/src/components/service/components/NextBtn.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 下一步 12 | 13 | 14 | 15 | 16 | 25 | -------------------------------------------------------------------------------- /miniprogram/src/components/service/components/Tabs.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ item.showName }} 10 | 11 | 12 | 13 | 14 | 15 | 32 | 61 | -------------------------------------------------------------------------------- /miniprogram/src/components/service/errands/WeightPicker.vue: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 物品重量 10 | 11 | {{ arr[active].weightText }} 12 | 13 | 14 | 15 | 16 | 17 | 52 | 61 | -------------------------------------------------------------------------------- /miniprogram/src/components/service/express/ExpressInfo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 描述 9 | 10 | {{ info.priceDetails.desc }} 11 | 12 | 13 | 64 | -------------------------------------------------------------------------------- /miniprogram/src/components/service/express/ExpressItem.vue: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | {{ options.name }} 8 | {{ options.price }} 元 11 | 12 | {{ options.desc }} 13 | 14 | 15 | 16 | 37 | 61 | -------------------------------------------------------------------------------- /miniprogram/src/components/service/move/MoveInfo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 11 | 16 | 17 | 描述 18 | 19 | {{ info.priceDetails.desc }} 20 | 21 | 22 | 49 | -------------------------------------------------------------------------------- /miniprogram/src/components/service/play/PlayInfo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 描述 7 | 8 | {{ info.priceDetails.desc }} 9 | 10 | 11 | 60 | -------------------------------------------------------------------------------- /miniprogram/src/components/service/software/SoftwareInfo.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 描述 6 | 7 | {{ info.priceDetails.desc }} 8 | 9 | 10 | 57 | -------------------------------------------------------------------------------- /miniprogram/src/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import App from "./App.vue"; 3 | import store from "@/store"; 4 | import "@/assets/font/iconfont.css"; 5 | import Button from "@/components/base/button/Button.vue"; 6 | import Tag from "@/components/base/tag/Tag.vue"; 7 | import Empty from "@/components/base/empty/Empty.vue"; 8 | import ScrollX from "@/components/base/scroll/ScrollX.vue"; 9 | import DImage from "@/components/base/image/image.vue"; 10 | import Watermark from "@/components/base/watermark/Watermark.vue"; 11 | 12 | Vue.component("DButton", Button); 13 | Vue.component("DTag", Tag); 14 | Vue.component("DEmpty", Empty); 15 | Vue.component("DScrollX", ScrollX); 16 | Vue.component("DImage", DImage); 17 | Vue.component("Watermark", Watermark); 18 | 19 | Vue.config.productionTip = false; 20 | Vue.prototype.$store = store; 21 | new App({ 22 | store, 23 | }).$mount(); 24 | -------------------------------------------------------------------------------- /miniprogram/src/mixins/service-mixin.vue: -------------------------------------------------------------------------------- 1 | 59 | -------------------------------------------------------------------------------- /miniprogram/src/pages/text/text.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 暂无无文本 5 | 6 | 7 | 8 | 9 | 10 | 50 | -------------------------------------------------------------------------------- /miniprogram/src/sfc.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.vue" { 2 | import Vue from "vue"; 3 | export default Vue; 4 | } 5 | -------------------------------------------------------------------------------- /miniprogram/src/static/avatar-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/avatar-card.png -------------------------------------------------------------------------------- /miniprogram/src/static/bus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/bus.jpg -------------------------------------------------------------------------------- /miniprogram/src/static/card-exam.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/card-exam.jpeg -------------------------------------------------------------------------------- /miniprogram/src/static/coupon-none.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/coupon-none.png -------------------------------------------------------------------------------- /miniprogram/src/static/cri_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/cri_right.png -------------------------------------------------------------------------------- /miniprogram/src/static/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/default.png -------------------------------------------------------------------------------- /miniprogram/src/static/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/edit.png -------------------------------------------------------------------------------- /miniprogram/src/static/empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/empty.png -------------------------------------------------------------------------------- /miniprogram/src/static/home-def.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/home-def.png -------------------------------------------------------------------------------- /miniprogram/src/static/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/home.png -------------------------------------------------------------------------------- /miniprogram/src/static/lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/lines.png -------------------------------------------------------------------------------- /miniprogram/src/static/mine-def.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/mine-def.png -------------------------------------------------------------------------------- /miniprogram/src/static/mine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/mine.png -------------------------------------------------------------------------------- /miniprogram/src/static/name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/name.png -------------------------------------------------------------------------------- /miniprogram/src/static/national-card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/national-card.png -------------------------------------------------------------------------------- /miniprogram/src/static/order-none.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/order-none.png -------------------------------------------------------------------------------- /miniprogram/src/static/order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/order.png -------------------------------------------------------------------------------- /miniprogram/src/static/order_def.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/order_def.png -------------------------------------------------------------------------------- /miniprogram/src/static/phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/phone.png -------------------------------------------------------------------------------- /miniprogram/src/static/print-excel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/print-excel.png -------------------------------------------------------------------------------- /miniprogram/src/static/print-pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/print-pdf.png -------------------------------------------------------------------------------- /miniprogram/src/static/print-ppt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/print-ppt.png -------------------------------------------------------------------------------- /miniprogram/src/static/print-word.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/print-word.png -------------------------------------------------------------------------------- /miniprogram/src/static/search-none.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/search-none.png -------------------------------------------------------------------------------- /miniprogram/src/static/shop-none.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdssssss/ddapp/3994bb452ccb1c0f199d903ae73450598ebb73ae/miniprogram/src/static/shop-none.png -------------------------------------------------------------------------------- /miniprogram/src/store/index.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | 4 | import profile from "./modules/profile"; 5 | import school from "./modules/school"; 6 | import publish from "./modules/publish"; 7 | import config from "./modules/config"; 8 | import coupon from "./modules/coupon"; 9 | import shop from "./modules/shop"; 10 | 11 | Vue.use(Vuex); 12 | interface IndexState { 13 | provider: string; 14 | } 15 | export default new Vuex.Store({ 16 | state: { 17 | provider: "", 18 | }, 19 | mutations: { 20 | setProvider(state: IndexState, value: string) { 21 | state.provider = value; 22 | }, 23 | }, 24 | modules: { 25 | profile, 26 | school, 27 | publish, 28 | config, 29 | coupon, 30 | shop, 31 | }, 32 | actions: {}, 33 | }); 34 | -------------------------------------------------------------------------------- /miniprogram/src/store/modules/coupon.ts: -------------------------------------------------------------------------------- 1 | interface State { 2 | unreadCoupons: any[]; 3 | showCouponModal: boolean; 4 | } 5 | export default { 6 | namespace: true, 7 | state: { 8 | unreadCoupons: [], 9 | showCouponModal: false, 10 | }, 11 | mutations: { 12 | setUnreadCoupons(state: State, val: any[]) { 13 | state.unreadCoupons = val; 14 | }, 15 | setShowCouponModal(state: State, val: boolean) { 16 | state.showCouponModal = val; 17 | }, 18 | }, 19 | actions: {}, 20 | }; 21 | -------------------------------------------------------------------------------- /miniprogram/src/store/modules/profile.ts: -------------------------------------------------------------------------------- 1 | interface State { 2 | nickName: string; 3 | avatarUrl: string; 4 | countryCode: string; 5 | mobileNumber: string; 6 | gender: number; 7 | userNo: string; 8 | } 9 | export default { 10 | namespace: true, 11 | state: { 12 | nickName: "", 13 | avatarUrl: "", 14 | countryCode: "", 15 | mobileNumber: "", 16 | gender: 0, 17 | userNo: "", 18 | } as State, 19 | mutations: { 20 | setProfile(state: State, data: any) { 21 | state.userNo = data.userNo; 22 | state.nickName = data.nickName; 23 | state.avatarUrl = data.avatarUrl; 24 | state.countryCode = data.countryCode; 25 | state.mobileNumber = data.mobileNumber; 26 | state.gender = data.gender; 27 | }, 28 | }, 29 | actions: {}, 30 | getters: {}, 31 | }; 32 | -------------------------------------------------------------------------------- /miniprogram/src/store/modules/publish.ts: -------------------------------------------------------------------------------- 1 | import { PublishAddressInterface } from "@/utils/constrants"; 2 | interface State { 3 | startAddress: PublishAddressInterface; 4 | endAddress: PublishAddressInterface; 5 | serviceDetails: any; 6 | serviceNanoid: string; 7 | serviceType: string; 8 | addressType: "double" | "start" | "end"; 9 | } 10 | export default { 11 | namespace: true, 12 | state: { 13 | startAddress: {}, 14 | endAddress: {}, 15 | serviceDetails: undefined, 16 | serviceNanoid: "", 17 | serviceType: "", 18 | addressType: "double", 19 | } as State, 20 | mutations: { 21 | setPublishData( 22 | state: State, 23 | params: { 24 | startAddress: PublishAddressInterface; 25 | endAddress: PublishAddressInterface; 26 | serviceDetails: any; 27 | serviceNanoid: string; 28 | serviceType: string; 29 | addressType: "double" | "start" | "end"; 30 | } 31 | ) { 32 | state.startAddress = params.startAddress; 33 | state.endAddress = params.endAddress; 34 | state.serviceNanoid = params.serviceNanoid; 35 | state.serviceDetails = params.serviceDetails; 36 | state.serviceType = params.serviceType; 37 | state.addressType = params.addressType; 38 | }, 39 | clearPublish(state: State) { 40 | state.startAddress = {}; 41 | state.endAddress = {}; 42 | state.serviceNanoid = ""; 43 | state.serviceDetails = undefined; 44 | state.serviceType = ""; 45 | state.addressType = "double"; 46 | }, 47 | }, 48 | actions: {}, 49 | getters: {}, 50 | }; 51 | -------------------------------------------------------------------------------- /miniprogram/src/uni.scss: -------------------------------------------------------------------------------- 1 | $primary: #0099ff; 2 | $success: #43cf7c; 3 | $warning: #f0ad4e; 4 | $error: #e82f1e; 5 | $info: #ff5733; 6 | $color-none: #e3e7ea; 7 | -------------------------------------------------------------------------------- /miniprogram/src/utils/constrants.ts: -------------------------------------------------------------------------------- 1 | export const API = () => { 2 | return "http://localhost:8001/api/"; 3 | }; 4 | export const SCHOOL_TYPE = "school"; 5 | 6 | export const AUTOCANCELTIME = 15 * 60 * 1000; 7 | export interface SchoolAddressOptions { 8 | area: string; 9 | areaId: number; 10 | build: string; 11 | buildId: number; 12 | detail: string; 13 | } 14 | 15 | // 发布的地址Interface 16 | export interface PublishAddressInterface { 17 | noneText?: string; // 无地址展示的内容 18 | schoolNo?: string; 19 | contactName?: string; 20 | mobileNumber?: string; 21 | province?: string; 22 | city?: string; 23 | district?: string; 24 | detail?: string; 25 | latitude?: string; 26 | longitude?: string; 27 | schoolBuild?: SchoolAddressOptions; 28 | } 29 | 30 | export type StatusType = 31 | | "all" 32 | | "waitPay" 33 | | "waitTake" 34 | | "waitSuccess" 35 | | "complete"; 36 | export type OrderTypeType = "user" | "taker"; 37 | -------------------------------------------------------------------------------- /miniprogram/src/utils/constrants.ts.bak: -------------------------------------------------------------------------------- 1 | const env = process.env.NODE_ENV; 2 | export const API = () => { 3 | if (env === "development") { 4 | return "http://localhost:8001/api/"; 5 | } 6 | return "{prod_api}/api/"; 7 | }; 8 | export const SCHOOL_TYPE = "{school_type}" as "school" | "community"; // or community 9 | export const SCHOOL_TYPE_LABEL = () => { 10 | return SCHOOL_TYPE === "school" ? "学校" : "社区"; 11 | }; 12 | export const AUTOCANCELTIME = 15 * 60 * 1000; 13 | export interface SchoolAddressOptions { 14 | area: string; 15 | areaId: number; 16 | build: string; 17 | buildId: number; 18 | detail: string; 19 | } 20 | 21 | // 发布的地址Interface 22 | export interface PublishAddressInterface { 23 | noneText?: string; // 无地址展示的内容 24 | schoolNo?: string; 25 | contactName?: string; 26 | mobileNumber?: string; 27 | province?: string; 28 | city?: string; 29 | district?: string; 30 | detail?: string; 31 | latitude?: string; 32 | longitude?: string; 33 | schoolBuild?: SchoolAddressOptions; 34 | } 35 | 36 | export type StatusType = 37 | | "all" 38 | | "waitPay" 39 | | "waitTake" 40 | | "waitSuccess" 41 | | "complete"; 42 | export type OrderTypeType = "user" | "taker"; 43 | -------------------------------------------------------------------------------- /miniprogram/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "esModuleInterop": true, 10 | "allowSyntheticDefaultImports": true, 11 | "experimentalDecorators":true, 12 | "sourceMap": true, 13 | "skipLibCheck": true, 14 | "baseUrl": ".", 15 | "types": [ 16 | "webpack-env", 17 | "@dcloudio/types", 18 | "miniprogram-api-typings", 19 | "mini-types" 20 | ], 21 | "paths": { 22 | "@/*": [ 23 | "./src/*" 24 | ] 25 | }, 26 | "lib": [ 27 | "esnext", 28 | "dom", 29 | "dom.iterable", 30 | "scripthost" 31 | ] 32 | }, 33 | "exclude": [ 34 | "node_modules", 35 | "unpackage", 36 | "src/**/*.nvue" 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /server/.editorconfig: -------------------------------------------------------------------------------- 1 | # 🎨 editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_style = space 9 | indent_size = 2 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true -------------------------------------------------------------------------------- /server/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/mwts/", 3 | "ignorePatterns": ["node_modules", "dist", "test", "jest.config.js", "typings"], 4 | "env": { 5 | "jest": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | logs/ 2 | npm-debug.log 3 | yarn-error.log 4 | node_modules/ 5 | package-lock.json 6 | coverage/ 7 | dist/ 8 | .idea/ 9 | run/ 10 | .DS_Store 11 | *.sw* 12 | *.un~ 13 | .tsbuildinfo 14 | .tsbuildinfo.* 15 | school/ 16 | community/ 17 | city/ 18 | public/ 19 | yarn.lock 20 | config.local.ts 21 | config.prod.ts 22 | config.dev.ts -------------------------------------------------------------------------------- /server/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('mwts/.prettierrc.json') 3 | } 4 | -------------------------------------------------------------------------------- /server/apidoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "码里码外接口文档", 3 | "version": "0.1.0", 4 | "description": "serverv2统一接口文档", 5 | "sampleUrl": "http://api.test.malimawai.cn/" 6 | } 7 | -------------------------------------------------------------------------------- /server/bootstrap.js: -------------------------------------------------------------------------------- 1 | const { Bootstrap } = require('@midwayjs/bootstrap'); 2 | Bootstrap.run(); 3 | -------------------------------------------------------------------------------- /server/ecosystem.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | apps: [ 3 | { 4 | name: 'ddrunv2-free', 5 | script: 'bootstrap.js', 6 | cwd: './', 7 | // 是否启用监控模式,默认是false。如果设置成true,当应用程序变动时,pm2会自动重载。这里也可以设置你要监控的文件。 8 | watch: false, 9 | env: { 10 | // 环境参数,当前指定为生产环境 process.env.NODE_ENV 11 | NODE_ENV: 'prod', 12 | }, 13 | }, 14 | ], 15 | }; 16 | -------------------------------------------------------------------------------- /server/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | testPathIgnorePatterns: ['/test/fixtures'], 5 | coveragePathIgnorePatterns: ['/test/'], 6 | setupFilesAfterEnv: ['./jest.setup.js'] 7 | }; 8 | -------------------------------------------------------------------------------- /server/jest.setup.js: -------------------------------------------------------------------------------- 1 | jest.setTimeout(30000); 2 | -------------------------------------------------------------------------------- /server/src/cert/readme.md: -------------------------------------------------------------------------------- 1 | cert 文件目录 2 | -------------------------------------------------------------------------------- /server/src/config/config.default.ts: -------------------------------------------------------------------------------- 1 | import { MidwayConfig, MidwayAppInfo } from '@midwayjs/core'; 2 | 3 | export default (appInfo: MidwayAppInfo) => { 4 | return { 5 | // use for cookie sign key, should change to your own and keep security 6 | keys: appInfo.name + '_1647247784657_5669', 7 | upload: { 8 | // mode: UploadMode, 默认为file,即上传到服务器临时目录,可以配置为 stream 9 | mode: 'file', 10 | // fileSize: string, 最大上传文件大小,默认为 10mb 11 | fileSize: '200mb', 12 | // whitelist: string[],文件扩展名白名单 13 | whitelist: [ 14 | '.jpg', 15 | '.jpeg', 16 | '.png', 17 | '.webp', 18 | '.doc', 19 | '.xls', 20 | '.ppt', 21 | '.pdf', 22 | '.docx', 23 | '.xlsx', 24 | '.pptx', 25 | ], 26 | // cleanTimeout: number,上传的文件在临时目录中多久之后自动删除,默认为 5 分钟 27 | cleanTimeout: 5 * 60 * 1000, 28 | }, 29 | bodyParser: { 30 | enableTypes: ['json', 'form', 'text', 'xml'], 31 | formLimit: '1mb', 32 | jsonLimit: '1mb', 33 | textLimit: '1mb', 34 | xmlLimit: '1mb', 35 | }, 36 | security: { 37 | csrf: { 38 | headerName: 'x-csrf-token', 39 | ignore: '/api', 40 | }, 41 | }, 42 | } as MidwayConfig; 43 | }; 44 | -------------------------------------------------------------------------------- /server/src/config/plugin.ts: -------------------------------------------------------------------------------- 1 | import { EggPlugin } from 'egg'; 2 | export default { 3 | // static: false, 4 | } as EggPlugin; 5 | -------------------------------------------------------------------------------- /server/src/configuration.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @apiDefine TestUrl 3 | * @apiSampleRequest http://api.test.malimawai.cn/ 4 | */ 5 | 6 | /** 7 | * @apiDefine AppHeaderCommon 8 | * @apiHeader {String} wxappno 微信平台用户识别编号 9 | * @apiHeader {String} token token 10 | * @apiHeader {String} version-name 版本 school or city or community 11 | */ 12 | 13 | import { App, Configuration } from '@midwayjs/decorator'; 14 | import { ILifeCycle, Inject } from '@midwayjs/core'; 15 | import { Application } from 'egg'; 16 | import { join } from 'path'; 17 | import * as egg from '@midwayjs/web'; 18 | import * as redis from '@midwayjs/redis'; 19 | import * as validate from '@midwayjs/validate'; 20 | import { AllErrorFilter } from './filter/all.filter'; 21 | import * as orm from '@midwayjs/orm'; 22 | import * as upload from '@midwayjs/upload'; 23 | import * as task from '@midwayjs/task'; 24 | import * as ws from '@midwayjs/ws'; 25 | import * as bull from '@midwayjs/bull'; 26 | // import { EverythingSubscriber } from './entity/subscriber'; 27 | 28 | @Configuration({ 29 | imports: [egg, redis, validate, orm, upload, task, ws, bull], 30 | importConfigs: [join(__dirname, './config')], 31 | }) 32 | export class ContainerLifeCycle implements ILifeCycle { 33 | @App() 34 | app: Application; 35 | 36 | @Inject() 37 | bullFramework: bull.Framework; 38 | 39 | async onReady() { 40 | this.app.useFilter([AllErrorFilter as any]); 41 | // await container.getAsync(EverythingSubscriber); 42 | // 创建队列自动执行一次 43 | const testQueue = this.bullFramework.createQueue('orderRobotAutoStart'); 44 | // 立即执行这个任务 45 | await testQueue?.runJob({}); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /server/src/controller/admin/map.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Inject, Query } from '@midwayjs/decorator'; 2 | import { Validate } from '@midwayjs/validate'; 3 | import { MapSearchDTO } from '../../dto/map.dto'; 4 | import { MapService } from '../../service/map.service'; 5 | import { BaseController } from '../base.controller'; 6 | 7 | @Controller('/admin/map') 8 | export class AdminMapController extends BaseController { 9 | @Inject() 10 | mapSerivce: MapService; 11 | 12 | @Get('/location/search') 13 | @Validate() 14 | async locationSearch(@Query() searchDTO: MapSearchDTO) { 15 | const result = await this.mapSerivce.locationSearch( 16 | searchDTO.keyword, 17 | `region(${searchDTO.cityName})`, 18 | searchDTO.current, 19 | searchDTO.pageSize 20 | ); 21 | return this.responseSuccess('ok', result); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /server/src/controller/admin/sts.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Inject } from '@midwayjs/decorator'; 2 | import { AdminMiddleware } from '../../middleware/admin.middleware'; 3 | import { STSService } from '../../service/ali/sts.service'; 4 | import { BaseController } from '../base.controller'; 5 | 6 | @Controller('/admin/sts', { middleware: [AdminMiddleware] }) 7 | export class STSController extends BaseController { 8 | @Inject() 9 | stsService: STSService; 10 | 11 | @Get('/') 12 | async getSTS() { 13 | return this.responseSuccess( 14 | 'ok', 15 | await this.stsService.getTempToken(this.ctx.adminInfo.adminNo) 16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /server/src/controller/admin/wxapp.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Inject, Query } from '@midwayjs/decorator'; 2 | import { Validate } from '@midwayjs/validate'; 3 | import { WxappListDTO } from '../../dto/wxapp.dto'; 4 | import { DefaultError } from '../../error/default.error'; 5 | import { AdminMiddleware } from '../../middleware/admin.middleware'; 6 | import { ConfigService } from '../../service/config.service'; 7 | import { QueryService } from '../../service/query.service'; 8 | import { WxappService } from '../../service/wxapp.service'; 9 | import { BaseController } from '../base.controller'; 10 | 11 | @Controller('/admin/wxapp', { middleware: [AdminMiddleware] }) 12 | export class AdminWxappController extends BaseController { 13 | @Inject() 14 | wxappService: WxappService; 15 | 16 | @Inject() 17 | queryService: QueryService; 18 | 19 | @Inject() 20 | configService: ConfigService; 21 | 22 | @Get('/list') 23 | @Validate() 24 | async list(@Query() dto: WxappListDTO) { 25 | if (this.ctx.adminInfo.isDemo) { 26 | throw new DefaultError('演示账户无权查看用户信息'); 27 | } 28 | let wheres = ''; 29 | if (dto.userNo) { 30 | wheres += `${wheres ? ' and ' : ''} userNo = '${dto.userNo}'`; 31 | } 32 | 33 | if (dto.openid) { 34 | wheres += `${wheres ? ' and ' : ''} openid = '${dto.openid}'`; 35 | } 36 | const result = await this.queryService.select( 37 | this.wxappService.wxappEntity, 38 | { 39 | tables: this.wxappService.wxappEntity.metadata.tableName, 40 | wheres, 41 | current: dto.current, 42 | pageSize: dto.pageSize, 43 | order: 'createTime desc', 44 | } 45 | ); 46 | return this.responseSuccess('ok', result); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /server/src/controller/api/baseapp/config.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Inject } from '@midwayjs/decorator'; 2 | import { 3 | CONFIG_PROTOCOL_SCHOOL, 4 | WXAPP_SUBSCRIBE_SCHOOL, 5 | CONFIG_TIME_REQUIREMENTS_SCHOOL, 6 | } from '../../../constant'; 7 | import { ConfigService } from '../../../service/config.service'; 8 | import { BaseController } from '../../base.controller'; 9 | 10 | @Controller('/api/baseapp/config') 11 | export class BaseappConfigController extends BaseController { 12 | @Inject() 13 | configService: ConfigService; 14 | 15 | @Get('/protocol') 16 | async getConfig() { 17 | const result = await this.configService.getConfig( 18 | CONFIG_PROTOCOL_SCHOOL, 19 | false 20 | ); 21 | return this.responseSuccess('ok', result); 22 | } 23 | 24 | /** 25 | * @api {get} api/baseapp/config/subscribe 获取订阅消息配置 26 | * @apiGroup 小程序 27 | * @apiName config-subscribe 28 | * @apiUse AppHeaderCommon 29 | * @apiParam {String} [provider] 小程序平台类型 如:weixin alipay 30 | */ 31 | @Get('/subscribe') 32 | async getSubscribe() { 33 | const result = await this.configService.getConfig( 34 | WXAPP_SUBSCRIBE_SCHOOL, 35 | false 36 | ); 37 | return this.responseSuccess('ok', result); 38 | } 39 | 40 | /** 41 | * @api {get} api/baseapp/config/time/requirement 获取时间配置 42 | * @apiGroup 小程序 43 | * @apiName config-time 44 | * @apiUse AppHeaderCommon 45 | * 46 | */ 47 | @Get('/time/requirement') 48 | async timeRequirementGet() { 49 | const result = await this.configService.getConfig( 50 | CONFIG_TIME_REQUIREMENTS_SCHOOL, 51 | false 52 | ); 53 | return this.responseSuccess('ok', result); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /server/src/controller/api/baseapp/richtext.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Query } from '@midwayjs/decorator'; 2 | import { InjectEntityModel } from '@midwayjs/orm'; 3 | import { Validate } from '@midwayjs/validate'; 4 | import { Repository } from 'typeorm'; 5 | import { RichtextInfoDTO } from '../../../dto/richtext.dto'; 6 | import { RichtextEntity } from '../../../entity/richtext.entity'; 7 | import { BaseController } from '../../base.controller'; 8 | 9 | @Controller('/api/baseapp/richtext') 10 | export class BaseappRichtextController extends BaseController { 11 | @InjectEntityModel(RichtextEntity) 12 | richtextEntity: Repository; 13 | 14 | @Get('/info') 15 | @Validate() 16 | async info(@Query() dto: RichtextInfoDTO) { 17 | const result = await this.richtextEntity.findOne({ 18 | where: { richNo: dto.richNo }, 19 | }); 20 | return this.responseSuccess('ok', result); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /server/src/controller/api/server.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get, Inject } from '@midwayjs/decorator'; 2 | import { Context } from 'egg'; 3 | import { UserMiddleware } from '../../middleware/user.middleware'; 4 | import { STSService } from '../../service/ali/sts.service'; 5 | import { BaseController } from '../base.controller'; 6 | 7 | @Controller('/api/server') 8 | export class ServerController extends BaseController { 9 | @Inject() 10 | stsService: STSService; 11 | 12 | @Inject() 13 | ctx: Context; 14 | 15 | // 获取身份信息 16 | @Get('/sts', { middleware: [UserMiddleware] }) 17 | async getCallerIdentity() { 18 | const res = await this.stsService.getTempToken(this.ctx.userInfo.userNo); 19 | return this.responseSuccess('ok', res); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /server/src/controller/api/sms.controller.ts: -------------------------------------------------------------------------------- 1 | import { Body, Controller, Inject, Post } from '@midwayjs/decorator'; 2 | import { BaseController } from '../base.controller'; 3 | import { MobileNumberDTO } from '../../dto/user.dto'; 4 | import { AliSmsService } from '../../service/ali/sms.service'; 5 | import { DefaultError } from '../../error/default.error'; 6 | 7 | @Controller('/api/sms') 8 | export class SmsController extends BaseController { 9 | @Inject() 10 | smsService: AliSmsService; 11 | @Post('/code') 12 | async getSmsCode(@Body() dto: MobileNumberDTO) { 13 | const { count } = await this.smsService.getSendVerifyCodeCount(); 14 | if (count >= 3) { 15 | throw new DefaultError('您的操作过于频繁,请稍后再试'); 16 | } 17 | const code = (Math.random() + '').split('.')[1].substring(0, 6); 18 | await this.smsService.sendSmsVerifyCode(dto.mobileNumber, code); 19 | await this.smsService.setSendVerifyRecord(code, dto.mobileNumber); 20 | await this.smsService.addSendVerifyCodeCount(); 21 | return this.responseSuccess('ok', '短信发送成功'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /server/src/controller/api/upload.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, File, Inject, Post } from '@midwayjs/decorator'; 2 | import { BaseController } from '../base.controller'; 3 | import { OSSService } from '../../service/ali/oss.service'; 4 | @Controller('/api/upload') 5 | export class AppUploadController extends BaseController { 6 | @Inject() 7 | uploadService: OSSService; 8 | 9 | @Post('/put') 10 | async upload(@File('file') file: File) { 11 | const result = await this.uploadService.put( 12 | file as any, 13 | this.ctx.headers['x-perfix'] as string 14 | ); 15 | return this.responseSuccess('ok', result); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /server/src/dto/address.dto.ts: -------------------------------------------------------------------------------- 1 | import { PickDto, Rule, RuleType } from '@midwayjs/validate'; 2 | import { SchoolAddress } from '../entity/userSchoolAddress.entity'; 3 | import { SelectCommonDTO } from './common.dto'; 4 | 5 | export class AddressAddDTO { 6 | @Rule(RuleType.string().max(45).empty('')) 7 | province: string; 8 | 9 | @Rule(RuleType.string().max(45).empty('')) 10 | city: string; 11 | 12 | @Rule(RuleType.string().max(45).empty('')) 13 | district: string; 14 | 15 | @Rule(RuleType.number().required()) 16 | latitude: number; 17 | 18 | @Rule(RuleType.number().required()) 19 | longitude: number; 20 | 21 | @Rule(RuleType.string().max(120).empty('')) 22 | detail: string; 23 | 24 | @Rule(RuleType.string().max(45).required()) 25 | contactName: string; 26 | 27 | @Rule(RuleType.string().length(11).required()) 28 | mobileNumber: string; 29 | 30 | @Rule(RuleType.object()) 31 | schoolBuild: SchoolAddress; 32 | 33 | @Rule(RuleType.boolean().required()) 34 | isDefault: boolean; 35 | } 36 | 37 | export class AddressUpdateDTO extends AddressAddDTO { 38 | @Rule(RuleType.string().length(16).required()) 39 | addressNo: string; 40 | } 41 | 42 | export class AddressDelDTO extends PickDto(AddressUpdateDTO, ['addressNo']) {} 43 | 44 | export class AddressListDTO extends SelectCommonDTO {} 45 | -------------------------------------------------------------------------------- /server/src/dto/analysis.dto.ts: -------------------------------------------------------------------------------- 1 | import { Rule, RuleType } from '@midwayjs/validate'; 2 | 3 | export class AnalysisDateDTO { 4 | @Rule(RuleType.string().required()) 5 | begin_date: string; 6 | @Rule(RuleType.string().required()) 7 | end_date: string; 8 | } 9 | 10 | export class AnalysisDayDTO { 11 | @Rule(RuleType.string().required()) 12 | beginDate: string; 13 | @Rule(RuleType.string().required()) 14 | endDate: string; 15 | } 16 | -------------------------------------------------------------------------------- /server/src/dto/bank.dto.ts: -------------------------------------------------------------------------------- 1 | import { PickDto, Rule, RuleType } from '@midwayjs/validate'; 2 | import { SelectCommonDTO } from './common.dto'; 3 | 4 | export class BankAddDTO { 5 | @Rule(RuleType.string()) 6 | cardNo: string; 7 | 8 | @Rule(RuleType.string()) 9 | realname: string; 10 | 11 | @Rule(RuleType.string()) 12 | bankName: string; 13 | } 14 | 15 | export class BankUpdateDTO extends BankAddDTO { 16 | @Rule(RuleType.string()) 17 | bankNo: string; 18 | } 19 | 20 | export class BankDelDTO extends PickDto(BankUpdateDTO, ['bankNo']) {} 21 | export class BankListDTO extends SelectCommonDTO { 22 | @Rule(RuleType.string().empty('')) 23 | bankNo?: string; 24 | 25 | @Rule(RuleType.string().empty('')) 26 | realname?: string; 27 | 28 | @Rule(RuleType.string().empty('')) 29 | cardNo?: string; 30 | 31 | @Rule(RuleType.string().empty('')) 32 | bankName?: string; 33 | } 34 | -------------------------------------------------------------------------------- /server/src/dto/cash.dto.ts: -------------------------------------------------------------------------------- 1 | import { Rule, RuleType } from '@midwayjs/validate'; 2 | import { SelectCommonDTO } from './common.dto'; 3 | 4 | export class CashRegisterDTO { 5 | @Rule(RuleType.number()) 6 | amount: number; 7 | 8 | @Rule(RuleType.string()) 9 | bankNo: string; 10 | } 11 | 12 | export class CashListDTO extends SelectCommonDTO { 13 | @Rule(RuleType.string()) 14 | cashBy?: 'rider' | 'user' | 'agent'; 15 | 16 | @Rule(RuleType.string()) 17 | cashNo?: string; 18 | 19 | @Rule(RuleType.number()) 20 | status?: number; 21 | 22 | @Rule(RuleType.string()) 23 | bankName?: string; 24 | 25 | @Rule(RuleType.string()) 26 | cardNo?: string; 27 | 28 | @Rule(RuleType.string()) 29 | realname?: string; 30 | } 31 | 32 | export class CashSuccessDTO { 33 | @Rule(RuleType.string().required()) 34 | cashNo: string; 35 | } 36 | 37 | export class CashFailDTO extends CashSuccessDTO { 38 | @Rule(RuleType.string().required()) 39 | reason: string; 40 | } 41 | 42 | export class CashAlipayExportExcelDTO { 43 | @Rule(RuleType.number().required()) 44 | count: number; 45 | } 46 | -------------------------------------------------------------------------------- /server/src/dto/common.dto.ts: -------------------------------------------------------------------------------- 1 | import { Rule, RuleType } from '@midwayjs/validate'; 2 | 3 | export class SelectCommonDTO { 4 | @Rule(RuleType.number().default(1)) 5 | current?: number; 6 | 7 | @Rule(RuleType.number().default(10)) 8 | pageSize?: number; 9 | } 10 | export const requiredStatus = RuleType.number().integer().min(0).max(1).required(); -------------------------------------------------------------------------------- /server/src/dto/coupon.dto.ts: -------------------------------------------------------------------------------- 1 | import { PickDto, Rule, RuleType } from '@midwayjs/validate'; 2 | import { ServerType } from '../interface'; 3 | import { SelectCommonDTO } from './common.dto'; 4 | 5 | export class CouponAddDTO { 6 | @Rule(RuleType.string().required().max(45)) 7 | couponName: string; 8 | 9 | @Rule(RuleType.number().required()) 10 | deadlineDays: number; 11 | 12 | @Rule(RuleType.number().required()) 13 | discountAmount: number; 14 | 15 | @Rule(RuleType.number()) 16 | conditionsAmount?: number; 17 | 18 | @Rule(RuleType.string().required()) 19 | conditionService: ServerType | 'ALL'; 20 | 21 | @Rule(RuleType.number()) 22 | limitNumber: number; 23 | 24 | @Rule(RuleType.number().required()) 25 | status: 0 | 1; 26 | } 27 | 28 | export class CouponUpdateDTO extends CouponAddDTO { 29 | @Rule(RuleType.string().required()) 30 | couponNo: string; 31 | } 32 | 33 | export class CouponStatusDTO extends PickDto(CouponUpdateDTO, [ 34 | 'couponNo', 35 | 'status', 36 | ]) {} 37 | 38 | export class CouponListDTO extends SelectCommonDTO { 39 | @Rule(RuleType.string()) 40 | couponNo?: string; 41 | 42 | @Rule(RuleType.string()) 43 | couponName?: string; 44 | 45 | @Rule(RuleType.string()) 46 | conditionService?: ServerType | 'ALL'; 47 | 48 | @Rule(RuleType.number()) 49 | status?: 0 | 1; 50 | } 51 | 52 | export class UserCouponListDTO { 53 | @Rule(RuleType.number()) 54 | price?: number; 55 | } 56 | 57 | export class CouponSendDTO { 58 | @Rule(RuleType.string().length(16).required()) 59 | couponNo: string; 60 | 61 | @Rule(RuleType.string().length(16).required()) 62 | userNo: string; 63 | } 64 | -------------------------------------------------------------------------------- /server/src/dto/errands.dto.ts: -------------------------------------------------------------------------------- 1 | import { PickDto, Rule, RuleType } from '@midwayjs/validate'; 2 | import { AddressType, RulesInterface } from '../entity/errandsTmplate.entity'; 3 | import { SelectCommonDTO } from './common.dto'; 4 | 5 | export class ErrandsAddDTO { 6 | @Rule(RuleType.string().required()) 7 | templateName: string; 8 | 9 | @Rule(RuleType.string().required()) 10 | showName: string; 11 | 12 | @Rule(RuleType.array().required()) 13 | weightRules: RulesInterface[]; 14 | 15 | @Rule(RuleType.array().required()) 16 | distanceRules: RulesInterface[]; 17 | 18 | @Rule(RuleType.array().required()) 19 | timeRules: RulesInterface[]; 20 | 21 | @Rule(RuleType.array().required()) 22 | tags: string[]; 23 | 24 | @Rule(RuleType.string().required()) 25 | startAddressType: AddressType; 26 | 27 | @Rule(RuleType.string().required()) 28 | startAddressPlaceholder: string; 29 | 30 | @Rule(RuleType.string().required()) 31 | endAddressType: AddressType; 32 | 33 | @Rule(RuleType.string().required()) 34 | endAddressPlaceholder: string; 35 | 36 | @Rule(RuleType.string().required()) 37 | descPlaceholder: string; 38 | } 39 | 40 | export class ErrandsUpdateDTO extends ErrandsAddDTO { 41 | @Rule(RuleType.number().required()) 42 | id: number; 43 | } 44 | 45 | export class ErrandsDelDTO extends PickDto(ErrandsUpdateDTO, ['id']) {} 46 | 47 | export class ErrandsListDTO extends SelectCommonDTO { 48 | @Rule(RuleType.string().empty('')) 49 | templateName: string; 50 | 51 | @Rule(RuleType.string().empty('')) 52 | showName: string; 53 | 54 | @Rule(RuleType.number()) 55 | id: number; 56 | } 57 | -------------------------------------------------------------------------------- /server/src/dto/file.dto.ts: -------------------------------------------------------------------------------- 1 | import { PickDto, Rule, RuleType } from '@midwayjs/validate'; 2 | import { SelectCommonDTO } from './common.dto'; 3 | 4 | export class FileGroupAddDTO { 5 | @Rule(RuleType.string().max(45).required()) 6 | groupName: string; 7 | 8 | @Rule(RuleType.string().max(10).required()) 9 | groupType: 'file' | 'richtext'; 10 | } 11 | 12 | export class FileGroupUpdateDTO extends FileGroupAddDTO { 13 | @Rule(RuleType.number().required()) 14 | id: number; 15 | } 16 | 17 | export class FileGroupDelDTO extends PickDto(FileGroupUpdateDTO, ['id']) {} 18 | 19 | export class FileAddDTO { 20 | @Rule(RuleType.string().max(45).required()) 21 | fileName: string; 22 | 23 | @Rule(RuleType.number().required()) 24 | fileSize: number; 25 | 26 | @Rule(RuleType.string().max(200).required()) 27 | fileLink: string; 28 | 29 | @Rule(RuleType.string().max(20).required()) 30 | suffix: string; 31 | 32 | @Rule(RuleType.number().empty('')) 33 | groupId?: number; 34 | } 35 | 36 | export class FileUpdateDTO extends FileAddDTO { 37 | @Rule(RuleType.number().required()) 38 | id: number; 39 | } 40 | 41 | export class FileDelDTO { 42 | @Rule(RuleType.string().required()) 43 | ids: string; 44 | } 45 | 46 | export class FileListDTO extends SelectCommonDTO { 47 | @Rule(RuleType.number().empty('')) 48 | groupId?: number; 49 | } 50 | 51 | export class FileMoveToGroupDTO extends FileDelDTO { 52 | @Rule(RuleType.number().required()) 53 | groupId: number; 54 | } 55 | -------------------------------------------------------------------------------- /server/src/dto/map.dto.ts: -------------------------------------------------------------------------------- 1 | import { Rule, RuleType } from '@midwayjs/validate'; 2 | 3 | export class MapLocationDTO { 4 | @Rule(RuleType.number().required()) 5 | latitude: number; 6 | 7 | @Rule(RuleType.number().required()) 8 | longitude: number; 9 | } 10 | 11 | export class MapSearchDTO { 12 | @Rule(RuleType.string().required()) 13 | cityName: string; 14 | 15 | @Rule(RuleType.string().required().empty('')) 16 | keyword: string; 17 | 18 | @Rule(RuleType.number()) 19 | current?: number; 20 | 21 | @Rule(RuleType.number()) 22 | pageSize?: number; 23 | } 24 | 25 | export class AddressParseDTO { 26 | @Rule(RuleType.string().required().empty()) 27 | keyword: string; 28 | } 29 | -------------------------------------------------------------------------------- /server/src/dto/order.dto.ts: -------------------------------------------------------------------------------- 1 | import { PickDto, Rule, RuleType } from '@midwayjs/validate'; 2 | 3 | export class OrderReceiveDTO { 4 | @Rule(RuleType.string().required()) 5 | orderNo: string; 6 | @Rule(RuleType.string().required()) 7 | riderNo: string; 8 | } 9 | 10 | export class OrderDeliverDTO extends PickDto(OrderReceiveDTO, ['orderNo']) {} 11 | 12 | export class OrderCancelDTO extends PickDto(OrderReceiveDTO, ['orderNo']) { 13 | @Rule(RuleType.string()) 14 | cancelReason?: string; 15 | } 16 | -------------------------------------------------------------------------------- /server/src/dto/richtext.dto.ts: -------------------------------------------------------------------------------- 1 | import { PickDto, Rule, RuleType } from '@midwayjs/validate'; 2 | import { SelectCommonDTO } from './common.dto'; 3 | 4 | export class RichtextAddDTO { 5 | @Rule(RuleType.string().max(50).required()) 6 | richTitle: string; 7 | 8 | @Rule(RuleType.string().max(200).required()) 9 | richImage: string; 10 | 11 | @Rule(RuleType.string().required()) 12 | richContent: string; 13 | 14 | @Rule(RuleType.number().empty('')) 15 | groupId?: number; 16 | } 17 | 18 | export class RichtextUpdateDTO extends RichtextAddDTO { 19 | @Rule(RuleType.string().length(16).required()) 20 | richNo: string; 21 | } 22 | export class RichtextDelDTO { 23 | @Rule(RuleType.string().required()) 24 | ids: string; 25 | } 26 | export class RichtextInfoDTO extends PickDto(RichtextUpdateDTO, ['richNo']) {} 27 | 28 | export class RichtextListDTO extends SelectCommonDTO { 29 | @Rule(RuleType.string().empty('')) 30 | richTitle?: string; 31 | 32 | @Rule(RuleType.number().empty('')) 33 | groupId?: number; 34 | } 35 | -------------------------------------------------------------------------------- /server/src/dto/taker.dto.ts: -------------------------------------------------------------------------------- 1 | import { Rule, RuleType } from '@midwayjs/validate'; 2 | import { CardImage } from '../entity/taker.entity'; 3 | import { SelectCommonDTO } from './common.dto'; 4 | 5 | export class TakerAddDTO { 6 | @Rule(RuleType.string().max(45).required()) 7 | realName: string; 8 | 9 | @Rule(RuleType.string().max(18).required()) 10 | idCard: string; 11 | 12 | @Rule(RuleType.object().required()) 13 | cardImages: CardImage; 14 | } 15 | 16 | export class AdminTakerAddDTO extends TakerAddDTO { 17 | @Rule(RuleType.string().length(16).required()) 18 | userNo: string; 19 | } 20 | 21 | export class AdminTakerListDTO extends SelectCommonDTO { 22 | @Rule(RuleType.string().empty('')) 23 | realName?: string; 24 | 25 | @Rule(RuleType.string().empty('')) 26 | idCard?: string; 27 | 28 | @Rule(RuleType.string().empty('')) 29 | userNo?: string; 30 | 31 | @Rule(RuleType.string().empty('')) 32 | takerNo?: string; 33 | 34 | @Rule(RuleType.number()) 35 | status?: 0 | -1 | 1; 36 | } 37 | 38 | export class AgentTakerListDTO extends AdminTakerListDTO { 39 | @Rule(RuleType.string().required()) 40 | schoolType: 'school' | 'community'; 41 | } 42 | 43 | export class AdminTakerPassDTO { 44 | @Rule(RuleType.string().required()) 45 | takerNo: string; 46 | } 47 | 48 | export class AdminTakerRefuseDTO extends AdminTakerPassDTO { 49 | @Rule(RuleType.string().required()) 50 | refuseMsg: string; 51 | } 52 | -------------------------------------------------------------------------------- /server/src/dto/wx.dto.ts: -------------------------------------------------------------------------------- 1 | import { PickDto, Rule, RuleType } from '@midwayjs/validate'; 2 | 3 | export class WxSubscribeAddTemplateDTO { 4 | @Rule(RuleType.string().required()) 5 | tid: string; 6 | 7 | @Rule(RuleType.array().required()) 8 | kidList: number[]; 9 | 10 | @Rule(RuleType.string()) 11 | sceneDesc?: string; 12 | } 13 | 14 | export class WxSubscribeDelTemplateDTO { 15 | @Rule(RuleType.string().required()) 16 | priTmplId: string; 17 | } 18 | 19 | export class WxSubscribeTmpKeyDTO extends PickDto(WxSubscribeAddTemplateDTO, [ 20 | 'tid', 21 | ]) {} 22 | 23 | export class WxGetpubtemplatetitlesDTO { 24 | @Rule(RuleType.string().required()) 25 | ids: string; 26 | @Rule(RuleType.number().required()) 27 | start: number; 28 | @Rule(RuleType.number().required()) 29 | limit: number; 30 | } 31 | 32 | export class WxSubscribeSendDTO { 33 | @Rule(RuleType.string().required()) 34 | touser: string; 35 | @Rule(RuleType.string().required()) 36 | template_id: string; 37 | @Rule(RuleType.string()) 38 | page?: string; 39 | @Rule(RuleType.object().required()) 40 | data: any; 41 | @Rule(RuleType.string()) 42 | miniprogram_state?: string; 43 | @Rule(RuleType.string()) 44 | lang?: string; 45 | } 46 | -------------------------------------------------------------------------------- /server/src/dto/wxapp.dto.ts: -------------------------------------------------------------------------------- 1 | import { Rule, RuleType } from '@midwayjs/validate'; 2 | import { SelectCommonDTO } from './common.dto'; 3 | 4 | export class WxappLoginDTO { 5 | @Rule(RuleType.string().required()) 6 | code: string; 7 | 8 | @Rule(RuleType.string().empty('')) 9 | fromNo?: string; 10 | 11 | @Rule(RuleType.string().empty('')) 12 | shareUserNo?: string; 13 | } 14 | 15 | export class WxappListDTO extends SelectCommonDTO { 16 | @Rule(RuleType.string().empty('')) 17 | userNo?: string; 18 | 19 | @Rule(RuleType.string().empty('')) 20 | openid?: string; 21 | } 22 | 23 | export class AlipayListDTO extends SelectCommonDTO { 24 | @Rule(RuleType.string().empty('')) 25 | userNo?: string; 26 | 27 | @Rule(RuleType.string().empty('')) 28 | aliUserId?: string; 29 | } 30 | 31 | export class WxappUploadDTO { 32 | @Rule(RuleType.string().required()) 33 | httpUrl: string; 34 | 35 | @Rule(RuleType.string().required()) 36 | appName: string; 37 | } 38 | -------------------------------------------------------------------------------- /server/src/entity/Base.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Column, 3 | CreateDateColumn, 4 | PrimaryGeneratedColumn, 5 | UpdateDateColumn, 6 | } from 'typeorm'; 7 | 8 | export class Base { 9 | @PrimaryGeneratedColumn() 10 | id: number; 11 | 12 | @CreateDateColumn() 13 | createTime: Date; 14 | 15 | @UpdateDateColumn() 16 | updateTime: Date; 17 | } 18 | 19 | export class CommonBase extends Base { 20 | @Column({ type: 'boolean', default: false, comment: '软删除' }) 21 | isDelete: boolean; 22 | } 23 | 24 | export class CommonAdminAgentBase extends CommonBase { 25 | @Column({ type: 'varchar', length: 16, comment: '操作人 admin or agent' }) 26 | updatedFrom: string; 27 | 28 | @Column({ type: 'char', length: 16, comment: '操作人No' }) 29 | updatedBy: string; 30 | } 31 | 32 | export class CommonAdminBase extends CommonBase { 33 | @Column({ type: 'char', length: 16, comment: '操作人No' }) 34 | updatedBy: string; 35 | } 36 | -------------------------------------------------------------------------------- /server/src/entity/admin.entity.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column, Unique } from 'typeorm'; 3 | import { Base } from './Base'; 4 | 5 | @EntityModel('admins') 6 | @Unique(['adminName']) 7 | export class AdminEntity extends Base { 8 | @Column({ type: 'varchar', length: 16, unique: true, comment: '管理员编号' }) 9 | adminNo: string; 10 | 11 | @Column({ type: 'varchar', length: 30, comment: '账号' }) 12 | adminName: string; 13 | 14 | @Column({ type: 'varchar', length: 40, nullable: true, comment: '密码' }) 15 | adminPwd: string; 16 | 17 | @Column({ type: 'int', default: 1, comment: '状态' }) 18 | status: 0 | 1; 19 | 20 | @Column({ type: 'varchar', length: 45, comment: '真实姓名' }) 21 | realName: string; 22 | 23 | @Column({ type: 'varchar', length: 11, comment: '手机号' }) 24 | mobileNumber: string; 25 | 26 | @Column({ type: 'varchar', length: 6, nullable: true, comment: '默认密码' }) 27 | defaultPwd: string; 28 | 29 | @Column({ type: 'boolean', default: false, comment: '超级管理员' }) 30 | superAdmin: boolean; 31 | 32 | @Column({ type: 'varchar', length: 200, comment: '头像', nullable: true }) 33 | avatarUrl: string; 34 | 35 | @Column({ 36 | type: 'varchar', 37 | length: 16, 38 | nullable: true, 39 | comment: '管理员编号', 40 | }) 41 | updatedBy: string; 42 | 43 | @Column({ 44 | type: 'boolean', 45 | default: false, 46 | comment: '是否是演示账户', 47 | }) 48 | isDemo: boolean; 49 | } 50 | -------------------------------------------------------------------------------- /server/src/entity/banks.entity.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column } from 'typeorm'; 3 | import { CommonBase } from './Base'; 4 | 5 | @EntityModel('banks') 6 | export class BanksEntity extends CommonBase { 7 | @Column({ type: 'char', length: 16, comment: '编号' }) 8 | bankNo: string; 9 | 10 | @Column({ type: 'varchar', length: 32, comment: '银行卡号' }) 11 | cardNo: string; 12 | 13 | @Column({ type: 'varchar', length: 30, comment: '账户姓名' }) 14 | realname: string; 15 | 16 | @Column({ type: 'varchar', length: 100, comment: '开户行' }) 17 | bankName: string; 18 | 19 | @Column({ type: 'char', length: 16, comment: '编号' }) 20 | userNo: string; 21 | } 22 | -------------------------------------------------------------------------------- /server/src/entity/cash.entity.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column } from 'typeorm'; 3 | import { Base } from './Base'; 4 | 5 | @EntityModel('cash') 6 | export class CashEntity extends Base { 7 | @Column({ type: 'char', length: 16, unique: true, comment: '提现编号' }) 8 | cashNo: string; 9 | 10 | @Column({ type: 'varchar', length: 12, comment: '提现用户类型' }) 11 | cashBy: 'user' | 'taker'; 12 | 13 | @Column({ type: 'char', length: 16, comment: '提现用户' }) 14 | cashByNo: string; 15 | 16 | @Column({ 17 | type: 'int', 18 | default: 0, 19 | comment: '提现状态 0 待提现 1提现成功 -1提现失败', 20 | }) 21 | status: 0 | 1 | -1; 22 | 23 | @Column({ type: 'double', comment: '提现金额' }) 24 | amount: number; 25 | 26 | @Column({ type: 'char', length: 16, comment: '提现账户' }) 27 | bankNo: string; 28 | 29 | @Column({ type: 'varchar', length: 100, nullable: true, comment: '提现理由' }) 30 | reason: string; 31 | } 32 | -------------------------------------------------------------------------------- /server/src/entity/config.entity.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column, Unique } from 'typeorm'; 3 | import { Base } from './Base'; 4 | 5 | @EntityModel('configs') 6 | @Unique(['configKey']) 7 | export class ConfigEntity extends Base { 8 | @Column({ type: 'varchar', length: 45, comment: '关键key' }) 9 | configKey: string; 10 | 11 | @Column({ type: 'json', comment: '配置内容' }) 12 | configContext: any; 13 | 14 | @Column({ type: 'char', length: 16, comment: '管理员' }) 15 | updatedBy: string; 16 | } 17 | -------------------------------------------------------------------------------- /server/src/entity/errandsTmplate.entity.ts: -------------------------------------------------------------------------------- 1 | export interface RulesInterface { 2 | gt: number; 3 | lte: number; 4 | unit?: number; 5 | price: number; 6 | } 7 | 8 | export type AddressType = 'nearby' | 'address' | 'none'; 9 | -------------------------------------------------------------------------------- /server/src/entity/fileGroup.entity.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column } from 'typeorm'; 3 | import { CommonAdminBase } from './Base'; 4 | 5 | @EntityModel('file_group') 6 | export class FileGroupEntity extends CommonAdminBase { 7 | @Column({ type: 'varchar', length: 45, comment: '组名' }) 8 | groupName: string; 9 | 10 | @Column({ type: 'varchar', length: 10, default: 'file', comment: '组类型' }) 11 | groupType: 'file' | 'richtext'; 12 | 13 | @Column({ 14 | type: 'varchar', 15 | length: 16, 16 | default: 'admin', 17 | comment: '操作人 admin or agent', 18 | }) 19 | updatedFrom: string; 20 | } 21 | -------------------------------------------------------------------------------- /server/src/entity/files.entity.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column } from 'typeorm'; 3 | import { CommonAdminBase } from './Base'; 4 | 5 | @EntityModel('files') 6 | export class FilesEntity extends CommonAdminBase { 7 | @Column({ type: 'varchar', length: 45, comment: '文件名' }) 8 | fileName: string; 9 | 10 | @Column({ type: 'int', comment: '文件尺寸' }) 11 | fileSize: number; 12 | 13 | @Column({ type: 'varchar', length: 200, comment: '文件链接' }) 14 | fileLink: string; 15 | 16 | @Column({ type: 'varchar', length: 20, comment: '文件后缀' }) 17 | suffix: string; 18 | 19 | @Column({ type: 'int', nullable: true, comment: '文件后缀' }) 20 | groupId: number; 21 | } 22 | -------------------------------------------------------------------------------- /server/src/entity/richtext.entity.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column } from 'typeorm'; 3 | import { CommonAdminBase } from './Base'; 4 | 5 | @EntityModel('richtext') 6 | export class RichtextEntity extends CommonAdminBase { 7 | @Column({ type: 'char', length: 16, comment: '编号' }) 8 | richNo: string; 9 | 10 | @Column({ type: 'varchar', length: 50, comment: '标题' }) 11 | richTitle: string; 12 | 13 | @Column({ type: 'varchar', length: 200, comment: '封面' }) 14 | richImage: string; 15 | 16 | @Column({ type: 'text', comment: '文本内容' }) 17 | richContent: string; 18 | 19 | @Column({ type: 'int', default: 0, comment: '组ID' }) 20 | groupId: number; 21 | } 22 | -------------------------------------------------------------------------------- /server/src/entity/school.entity.ts: -------------------------------------------------------------------------------- 1 | export interface ServiceData { 2 | nanoid: string; 3 | type: string; 4 | label: string; 5 | image: string; 6 | serviceTempNo?: string; 7 | extractForPlatform?: number; // 平台抽点 8 | extractForAgent?: number; // 代理抽点 9 | link?: string; 10 | intoHall?: boolean; 11 | express?: any[]; 12 | tags?: string[]; 13 | weightRules?: Rule[]; 14 | } 15 | interface Rule { 16 | gt: number; 17 | lte: number; 18 | unit?: number; 19 | price: number; 20 | } 21 | export interface ServiceObject { 22 | iconInWhere: string; 23 | sortStyle: string; // 排序方式 24 | services: ServiceData[]; 25 | } 26 | 27 | export interface TakeOutSetting { 28 | distanceRules: Rule[]; 29 | timeRules: Rule[]; 30 | intoHall: boolean; 31 | startPrice: number; 32 | plateformRate: number; 33 | agentRate: number; 34 | } 35 | -------------------------------------------------------------------------------- /server/src/entity/schoolArea.entity.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column } from 'typeorm'; 3 | import { CommonAdminAgentBase } from './Base'; 4 | 5 | @EntityModel('school_area') 6 | export class SchoolAreaEntity extends CommonAdminAgentBase { 7 | @Column({ type: 'varchar', length: 45, comment: '区域名称' }) 8 | areaName: string; 9 | 10 | @Column({ type: 'int', comment: '显示状态' }) 11 | status: 0 | 1; 12 | } 13 | -------------------------------------------------------------------------------- /server/src/entity/schoolBalanceSheet.entity.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column, Unique } from 'typeorm'; 3 | import { Base } from './Base'; 4 | @EntityModel('school_balance_sheet') 5 | @Unique(['orderNo']) 6 | export class SchoolBalanceSheetEntity extends Base { 7 | @Column({ type: 'varchar', length: 50, comment: '订单编号' }) 8 | orderNo: string; 9 | 10 | @Column({ type: 'char', length: 16, comment: '接单员编号' }) 11 | takerNo: string; 12 | 13 | @Column({ type: 'double', comment: '平台收入' }) 14 | platformIncome: number; 15 | 16 | @Column({ type: 'double', comment: '接单员收入' }) 17 | takerIncome: number; 18 | 19 | @Column({ type: 'varchar', length: 100, nullable: true, comment: '描述' }) 20 | desc: string; 21 | } 22 | -------------------------------------------------------------------------------- /server/src/entity/schoolBuilding.entity.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column } from 'typeorm'; 3 | import { CommonAdminAgentBase } from './Base'; 4 | 5 | @EntityModel('school_building') 6 | export class SchoolBuildingEntity extends CommonAdminAgentBase { 7 | @Column({ type: 'varchar', length: 45, comment: '建筑物名称' }) 8 | buildName: string; 9 | 10 | @Column({ type: 'varchar', length: 45, comment: '备注', nullable: true }) 11 | remark: string; 12 | 13 | @Column({ type: 'int', comment: '区域id' }) 14 | areaId: number; 15 | 16 | @Column({ type: 'varchar', length: 100, comment: '纬度经度' }) 17 | latlng: string; 18 | } 19 | -------------------------------------------------------------------------------- /server/src/entity/schoolCarousels.entity.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column } from 'typeorm'; 3 | import { CommonAdminAgentBase } from './Base'; 4 | 5 | export interface BannerInterface { 6 | image: string; 7 | path: string; 8 | } 9 | @EntityModel('school_carousels') 10 | export class SchoolCarouselsEnitty extends CommonAdminAgentBase { 11 | @Column({ type: 'char', length: 16, unique: true, comment: '编号' }) 12 | carouselNo: string; 13 | 14 | @Column({ type: 'json', comment: '广告图' }) 15 | banners: BannerInterface[]; 16 | } 17 | -------------------------------------------------------------------------------- /server/src/entity/taker.entity.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column, Unique } from 'typeorm'; 3 | import { Base } from './Base'; 4 | const uniqueArr = ['userNo']; 5 | 6 | export interface CardImage { 7 | studentCard?: string; // 学生证 8 | avatarFaceImage?: string; // 头像一面的身份证照片 9 | nationalFaceImage?: string; // 国徽一面的身份证照片 10 | } 11 | // 接单员 12 | @EntityModel('taker') 13 | @Unique(uniqueArr) 14 | export class TakerEntity extends Base { 15 | @Column({ type: 'char', length: 16, unique: true, comment: '接单员编号' }) 16 | takerNo: string; 17 | 18 | @Column({ type: 'int', default: 0, comment: '状态' }) 19 | status: 0 | 1 | -1; 20 | 21 | @Column({ type: 'char', length: 16, comment: '用户编号' }) 22 | userNo: string; 23 | 24 | @Column({ type: 'varchar', length: 45, comment: '真实姓名' }) 25 | realName: string; 26 | 27 | @Column({ 28 | type: 'varchar', 29 | length: 18, 30 | comment: '身份证号或学号', 31 | }) 32 | idCard: string; 33 | 34 | @Column({ 35 | type: 'varchar', 36 | length: 16, 37 | nullable: true, 38 | comment: '学校编号', 39 | }) 40 | schoolNo: string; 41 | 42 | @Column({ type: 'json', comment: '身份证或学生证照片' }) 43 | cardImages: CardImage; 44 | 45 | @Column({ type: 'varchar', length: 100, nullable: true, comment: '拒绝理由' }) 46 | refuseMsg: string; 47 | 48 | @Column({ type: 'json', comment: '来自那个端' }) 49 | fromClient: { 50 | provider: string; 51 | openid?: string; // 用户编号 52 | aliUserId?: string; // 用户编号 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /server/src/entity/user.entity.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column, Unique } from 'typeorm'; 3 | import { Base } from './Base'; 4 | 5 | @EntityModel('users') 6 | @Unique(['mobileNumber']) 7 | export class UserEntity extends Base { 8 | @Column({ type: 'char', length: 16, unique: true, comment: '用户编号' }) 9 | userNo: string; 10 | 11 | @Column({ type: 'varchar', length: 10, default: '86', comment: '国家代码' }) 12 | countryCode: string; 13 | 14 | @Column({ type: 'varchar', length: 11, comment: '手机号' }) 15 | mobileNumber: string; 16 | 17 | @Column({ type: 'varchar', length: 200, nullable: true, comment: '头像' }) 18 | avatarUrl: string; 19 | 20 | @Column({ type: 'varchar', length: 45, comment: '昵称' }) 21 | nickName: string; 22 | 23 | @Column({ type: 'int', default: 0, comment: '性别 0未知,1男 2女' }) 24 | gender: 0 | 1 | 2; 25 | 26 | @Column({ type: 'varchar', length: 45, nullable: true, comment: '省' }) 27 | province: string; 28 | 29 | @Column({ type: 'varchar', length: 45, nullable: true, comment: '市' }) 30 | city: string; 31 | 32 | @Column({ type: 'varchar', length: 45, nullable: true, comment: '区' }) 33 | area: string; 34 | 35 | @Column({ type: 'int', default: 1, comment: '状态 0禁用 1启用' }) 36 | status: 0 | 1; 37 | 38 | @Column({ type: 'char', length: 16, nullable: true, comment: '校园默认地址' }) 39 | schoolAddress: string; 40 | 41 | @Column({ type: 'boolean', default: 0, comment: '是否已认证' }) 42 | isIdentity: boolean; 43 | 44 | @Column({ 45 | type: 'varchar', 46 | length: 16, 47 | nullable: true, 48 | comment: '注册来自哪个城市或学校', 49 | }) 50 | fromNo: string; 51 | 52 | @Column({ type: 'varchar', nullable: true, comment: '认证方' }) 53 | identityBy: 'weixin' | 'alipay' | 'platform'; 54 | } 55 | -------------------------------------------------------------------------------- /server/src/entity/userCoupon.entity.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column } from 'typeorm'; 3 | import { CommonBase } from './Base'; 4 | 5 | @EntityModel('user_coupon') 6 | export class UserCouponEntity extends CommonBase { 7 | @Column({ type: 'char', length: 16, comment: '优惠券编号' }) 8 | couponNo: string; 9 | 10 | @Column({ type: 'char', length: 16, comment: '用户编号' }) 11 | userNo: string; 12 | 13 | @Column({ type: 'varchar', length: 13, nullable: true, comment: '过期时间' }) 14 | deadlineTime: number; 15 | 16 | @Column({ type: 'boolean', default: false, comment: '是否使用' }) 17 | isUse: boolean; 18 | 19 | @Column({ type: 'boolean', default: false, comment: '是否已查看' }) 20 | isLook: boolean; 21 | 22 | @Column({ type: 'varchar', length: 100, nullable: true, comment: '来源描述' }) 23 | originDesc: string; 24 | } 25 | -------------------------------------------------------------------------------- /server/src/entity/userSchoolAddress.entity.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column } from 'typeorm'; 3 | import { CommonBase } from './Base'; 4 | 5 | export interface SchoolAddress { 6 | area: string; 7 | areaId: number; 8 | build: string; 9 | buildId: number; 10 | detail: string; 11 | } 12 | 13 | @EntityModel('users_school_address') 14 | export class UserSchoolAddressEntity extends CommonBase { 15 | @Column({ type: 'char', length: 16, unique: true }) 16 | addressNo: string; 17 | 18 | @Column({ type: 'varchar', length: 45, comment: '省' }) 19 | province: string; 20 | 21 | @Column({ type: 'varchar', length: 45, comment: '市' }) 22 | city: string; 23 | 24 | @Column({ type: 'varchar', length: 45, comment: '区' }) 25 | district: string; 26 | 27 | @Column({ type: 'double', comment: '纬度' }) 28 | latitude: number; 29 | 30 | @Column({ type: 'double', comment: '经度' }) 31 | longitude: number; 32 | 33 | @Column({ type: 'varchar', length: 120, nullable: true, comment: '详细地址' }) 34 | detail: string; 35 | 36 | @Column({ type: 'char', length: 16 }) 37 | userNo: string; 38 | 39 | @Column({ type: 'varchar', length: 45, comment: '联系人姓名' }) 40 | contactName: string; 41 | 42 | @Column({ type: 'char', length: 11, comment: '联系人手机号' }) 43 | mobileNumber: string; 44 | 45 | @Column({ type: 'json', nullable: true, comment: '学校地址' }) 46 | schoolBuild: SchoolAddress; 47 | } 48 | -------------------------------------------------------------------------------- /server/src/entity/wxapp.entity.ts: -------------------------------------------------------------------------------- 1 | import { EntityModel } from '@midwayjs/orm'; 2 | import { Column, Unique } from 'typeorm'; 3 | import { Base } from './Base'; 4 | const uniqueArr = ['openid']; 5 | 6 | @EntityModel('wxapp') 7 | @Unique(uniqueArr) 8 | export class WxappEntity extends Base { 9 | @Column({ type: 'char', length: 32, unique: true, comment: '微信用户编号' }) 10 | wxappNo: string; 11 | 12 | @Column({ type: 'varchar', length: 32 }) 13 | openid: string; 14 | 15 | @Column({ type: 'char', length: 16, nullable: true }) 16 | userNo: string; 17 | } 18 | -------------------------------------------------------------------------------- /server/src/error/config.error.ts: -------------------------------------------------------------------------------- 1 | import { MidwayHttpError } from '@midwayjs/core'; 2 | 3 | export class ConfigError extends MidwayHttpError { 4 | constructor(message: string) { 5 | super(message, 1003); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /server/src/error/default.error.ts: -------------------------------------------------------------------------------- 1 | import { MidwayHttpError } from '@midwayjs/core'; 2 | 3 | export class DefaultError extends MidwayHttpError { 4 | constructor(message: string) { 5 | super(message, 1000); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /server/src/error/login.error.ts: -------------------------------------------------------------------------------- 1 | import { MidwayHttpError } from '@midwayjs/core'; 2 | 3 | export class LoginError extends MidwayHttpError { 4 | constructor(message: string) { 5 | super(message, 203); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /server/src/error/notice.error.ts: -------------------------------------------------------------------------------- 1 | import { MidwayHttpError } from '@midwayjs/core'; 2 | 3 | export class NoticeError extends MidwayHttpError { 4 | constructor(message: string, desc: string) { 5 | super(message, 1004, '1004', { 6 | cause: new Error(desc), 7 | }); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /server/src/error/setpwd.error.ts: -------------------------------------------------------------------------------- 1 | import { MidwayHttpError } from '@midwayjs/core'; 2 | 3 | export class SetpwdError extends MidwayHttpError { 4 | constructor(message: string) { 5 | super(message, 202); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /server/src/error/taker.error.ts: -------------------------------------------------------------------------------- 1 | import { MidwayHttpError } from '@midwayjs/core'; 2 | 3 | export class TakerError extends MidwayHttpError { 4 | constructor(message: string) { 5 | super(message, 1002); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /server/src/filter/all.filter.ts: -------------------------------------------------------------------------------- 1 | import { Catch } from '@midwayjs/decorator'; 2 | import { Context } from 'egg'; 3 | import { ResultResponse } from '../interface'; 4 | interface ErrorFilter extends Error { 5 | status?: number; 6 | } 7 | @Catch() 8 | export class AllErrorFilter { 9 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 10 | async catch(err: ErrorFilter, _ctx: Context): Promise { 11 | const result = { 12 | code: err.status || 1001, 13 | msg: err.message, 14 | data: null, 15 | }; 16 | switch (err.name) { 17 | case 'NotFoundError': 18 | result.code = 404; 19 | result.msg = '服务访问404'; 20 | break; 21 | case 'InternalServerErrorError': 22 | result.code = 500; 23 | result.msg = '服务端错误500'; 24 | break; 25 | } 26 | if (result.code === 1000) { 27 | console.error( 28 | '[ ServerError ]', 29 | _ctx.request.URL.pathname, 30 | new Date().toLocaleString(), 31 | result.msg 32 | ); 33 | } 34 | if (result.code === 422) { 35 | console.error( 36 | '[ ValidateError ]', 37 | new Date().toLocaleString(), 38 | result.msg 39 | ); 40 | } 41 | if (result.code === 1001) { 42 | console.error(err.stack); 43 | } 44 | 45 | if (result.code === 1004) { 46 | result.data = (err as any).cause.message; 47 | } 48 | return result; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /server/src/middleware/app.middleware.ts: -------------------------------------------------------------------------------- 1 | import { IMiddleware, NextFunction } from '@midwayjs/core'; 2 | import { Middleware } from '@midwayjs/decorator'; 3 | import { Context } from 'egg'; 4 | import { LoginError } from '../error/login.error'; 5 | import { WxappService } from '../service/wxapp.service'; 6 | 7 | @Middleware() 8 | export class AppMiddleware implements IMiddleware { 9 | resolve() { 10 | return async (ctx: Context, next: NextFunction) => { 11 | const wxappService = await ctx.requestContext.getAsync(WxappService); 12 | const wxappNo = ctx.request.header.wxappno as string; 13 | 14 | if (!wxappNo) { 15 | throw new LoginError('请重新登录'); 16 | } 17 | // 用户端类型 18 | let userType = ''; 19 | let user = null as any; 20 | if (wxappNo) { 21 | user = await wxappService.findByNo(wxappNo); 22 | userType = 'weixin'; 23 | } 24 | if (!user) { 25 | throw new LoginError('请重新登录'); 26 | } 27 | 28 | if (!user.userNo) { 29 | throw new LoginError('请先登录/注册'); 30 | } 31 | 32 | ctx.userInfo = Object.assign(user, { userType }); 33 | return await next(); 34 | }; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /server/src/middleware/user.middleware.ts: -------------------------------------------------------------------------------- 1 | import { IMiddleware, NextFunction } from '@midwayjs/core'; 2 | import { Middleware } from '@midwayjs/decorator'; 3 | import { Context } from 'egg'; 4 | import { DefaultError } from '../error/default.error'; 5 | import { LoginError } from '../error/login.error'; 6 | import { JWTService } from '../service/jwt.service'; 7 | import { UserService } from '../service/user.service'; 8 | 9 | @Middleware() 10 | export class UserMiddleware implements IMiddleware { 11 | resolve() { 12 | return async (ctx: Context, next: NextFunction) => { 13 | const jwtService = await ctx.requestContext.getAsync(JWTService); 14 | const userService = await ctx.requestContext.getAsync(UserService); 15 | const token = ctx.cookies.get('token'); 16 | if (!token) { 17 | throw new LoginError('请重新登录'); 18 | } 19 | const verifyResult = await jwtService.verify(token); 20 | if (verifyResult.isExpried) { 21 | // 过期 22 | throw new LoginError('回话过期,请重新登录'); 23 | } 24 | if (!verifyResult.userId) { 25 | console.log('------用户校验失败------', verifyResult); 26 | throw new DefaultError('用户校验失败'); 27 | } 28 | if (verifyResult.ip !== ctx.ip) { 29 | throw new LoginError('您已被强制下线'); 30 | } 31 | const userInfo = await userService.findById(verifyResult.userId); 32 | if (!userInfo) { 33 | throw new DefaultError('获取用户失败'); 34 | } 35 | if (!userInfo.id) { 36 | throw new DefaultError('用户不存在'); 37 | } 38 | if (userInfo.status === 0) { 39 | throw new DefaultError('您的账户已被限制'); 40 | } 41 | ctx.userInfo = userInfo; 42 | return await next(); 43 | }; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /server/src/service/ali/oss.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Provide } from '@midwayjs/decorator'; 2 | import { BaseService } from '../base.service'; 3 | import OSS = require('ali-oss'); 4 | import { ConfigService } from '../config.service'; 5 | import { CONFIG_ALI } from '../../constant'; 6 | import { AliDTO } from '../../dto/config.dto'; 7 | import { DefaultError } from '../../error/default.error'; 8 | 9 | @Provide() 10 | export class OSSService extends BaseService { 11 | @Inject() 12 | configService: ConfigService; 13 | 14 | async put(file: File & { filename: string; data: string }, perfix?: string) { 15 | const config = (await this.configService.getConfig(CONFIG_ALI)) as AliDTO; 16 | const client = new OSS({ 17 | // yourregion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。 18 | region: config.ossRegion, 19 | // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。 20 | accessKeyId: config.accessKeyId, 21 | accessKeySecret: config.accessKeySecret, 22 | // 填写Bucket名称。关于Bucket名称命名规范的更多信息,请参见Bucket。 23 | bucket: config.ossBucket, 24 | }); 25 | try { 26 | // 填写OSS文件完整路径和本地文件的完整路径。OSS文件完整路径中不能包含Bucket名称。 27 | // 如果本地文件的完整路径中未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。 28 | const split = file.filename.split('.'); 29 | const suffix = split[split.length - 1]; 30 | const name = `${perfix || ''}${this.nanoid(20)}.${suffix}`; 31 | const result = await client.put(name, file.data); 32 | let url = result.url; 33 | if (!result.url.includes('https')) { 34 | url = result.url.replace('http', 'https'); 35 | } 36 | return url; 37 | } catch (e) { 38 | throw new DefaultError(e.message); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /server/src/service/ali/sts.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Provide } from '@midwayjs/decorator'; 2 | import { CONFIG_ALI } from '../../constant'; 3 | import { AliDTO } from '../../dto/config.dto'; 4 | import { NoticeError } from '../../error/notice.error'; 5 | import { BaseService } from '../base.service'; 6 | import { ConfigService } from '../config.service'; 7 | const StsClient = require('@alicloud/sts-sdk'); 8 | /** 9 | * 使用STS临时访问凭证访问OSS 教程 10 | * https://help.aliyun.com/document_detail/100624.htm?spm=a2c4g.11186623.0.0.75565b78xKNESY#concept-xzh-nzk-2gb 11 | */ 12 | @Provide() 13 | export class STSService extends BaseService { 14 | @Inject() 15 | configService: ConfigService; 16 | 17 | async getTempToken(userNo: string) { 18 | const config = (await this.configService.getConfig(CONFIG_ALI)) as AliDTO; 19 | const sts = new StsClient({ 20 | endpoint: 'sts.aliyuncs.com', 21 | accessKeyId: config.accessKeyId, 22 | accessKeySecret: config.accessKeySecret, 23 | }); 24 | const res = await sts.assumeRole(config.arn, userNo); 25 | if (!res.Credentials) { 26 | throw new NoticeError('sts认证失败', res.Message); 27 | } 28 | return Object.assign(res.Credentials, { 29 | oss: { 30 | region: config.ossRegion, 31 | bucket: config.ossBucket, 32 | }, 33 | }); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /server/src/service/anlysis.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Provide } from '@midwayjs/decorator'; 2 | import { 3 | CONFIG_ALI, 4 | CONFIG_APPAUTH_INFO, 5 | CONFIG_APPMCH, 6 | CONFIG_MAPKEY, 7 | CONFIG_NOTICE, 8 | } from '../constant'; 9 | import { BaseService } from './base.service'; 10 | import { ConfigService } from './config.service'; 11 | 12 | @Provide() 13 | export class AnlysisService extends BaseService { 14 | @Inject() 15 | configService: ConfigService; 16 | 17 | // 小程序配置 18 | async getAppAuthRateInfo() { 19 | return this.fitlerInfoResult(CONFIG_APPAUTH_INFO); 20 | } 21 | 22 | // 支付信息配置 23 | async getAppMchRateInfo() { 24 | return this.fitlerInfoResult(CONFIG_APPMCH); 25 | } 26 | 27 | // 订阅消息配置 28 | async getSubscribeInfo() { 29 | return this.fitlerInfoResult(CONFIG_NOTICE); 30 | } 31 | 32 | // 地图配置 33 | async getMap() { 34 | return this.fitlerInfoResult(CONFIG_MAPKEY); 35 | } 36 | 37 | // 阿里云配置 38 | async getAli() { 39 | return this.fitlerInfoResult(CONFIG_ALI); 40 | } 41 | 42 | async fitlerInfoResult(configApp: string) { 43 | const configAppMch = await this.configService.getConfig(configApp, false); 44 | let complete = 0; 45 | let keyLen = 0; 46 | if (configAppMch) { 47 | const keys = Object.keys(configAppMch); 48 | keyLen = keys.length; 49 | for (const key of keys) { 50 | if (configAppMch[key]) { 51 | complete++; 52 | } 53 | } 54 | } 55 | return { 56 | complete, 57 | keyLen, 58 | rate: keyLen > 0 ? this.filterNumber((complete * 100) / keyLen) : 0, 59 | }; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /server/src/service/base.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Provide } from '@midwayjs/decorator'; 2 | // import { RedisService } from '@midwayjs/redis'; 3 | import { Context } from 'egg'; 4 | import { HttpService } from './http.service'; 5 | import { nanoid } from 'nanoid'; 6 | import { CustomConfig } from '../interface'; 7 | import { RedisService } from '@midwayjs/redis'; 8 | const env = process.env.NODE_ENV; 9 | const config = require(`../config/config.${env}`); 10 | 11 | @Provide() 12 | export class BaseService { 13 | @Inject() 14 | redis: RedisService; 15 | 16 | @Inject() 17 | ctx: Context; 18 | 19 | @Inject() 20 | http: HttpService; 21 | 22 | nanoid(len = 13) { 23 | return nanoid(len); 24 | } 25 | config(): CustomConfig { 26 | return config.default as CustomConfig; 27 | } 28 | 29 | filterNumber(num: number) { 30 | return Math.floor(Math.round(num * 100)) / 100; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /server/src/service/jwt.service.ts: -------------------------------------------------------------------------------- 1 | import { Provide } from '@midwayjs/decorator'; 2 | import { BaseService } from './base.service'; 3 | import { sign, verify } from 'jsonwebtoken'; 4 | import { LoginError } from '../error/login.error'; 5 | interface VerifyResult { 6 | isExpried?: boolean; 7 | userId?: number; 8 | ip?: string; 9 | userNo?: string; 10 | } 11 | 12 | @Provide() 13 | export class JWTService extends BaseService { 14 | sign(data: string | object | Buffer, expiresIn?: string) { 15 | const token = sign(data, this.config().jwt.privateKey, { 16 | expiresIn: expiresIn || this.config().jwt.expiresIn, 17 | }); 18 | return token; 19 | } 20 | async verify(token: string): Promise { 21 | return new Promise(resolve => { 22 | verify(token, this.config().jwt.privateKey, (err, decoded) => { 23 | if (err) { 24 | if (err.name === 'TokenExpiredError') { 25 | resolve({ isExpried: true }); 26 | } else { 27 | throw new LoginError(err.message); 28 | } 29 | // console.log(err); 30 | } 31 | resolve(decoded as any); 32 | }); 33 | }); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /server/src/service/redis.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Provide } from '@midwayjs/decorator'; 2 | import { Context } from 'egg'; 3 | import { RedisService } from '@midwayjs/redis'; 4 | 5 | @Provide() 6 | export class RedisCustomService { 7 | @Inject() 8 | redis: RedisService; 9 | 10 | @Inject() 11 | ctx: Context; 12 | 13 | filterSassKey(key: any) { 14 | return key; 15 | } 16 | 17 | async set( 18 | key: any, 19 | value: string | number | Buffer, 20 | secondsToken?: 'EX', 21 | seconds?: number 22 | ) { 23 | key = this.filterSassKey(key); 24 | if (secondsToken) { 25 | return await this.redis.set(key, value, secondsToken, seconds); 26 | } else { 27 | return await this.redis.set(key, value); 28 | } 29 | } 30 | 31 | async get(key: any) { 32 | key = this.filterSassKey(key); 33 | return await this.redis.get(key); 34 | } 35 | 36 | async del(key: any) { 37 | key = this.filterSassKey(key); 38 | return await this.redis.del(key); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /server/src/task/schoolOrder.task.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Provide, Queue } from '@midwayjs/decorator'; 2 | import { SchoolOrdersService } from '../service/schoolOrders.service'; 3 | 4 | // 自动关闭时间 5 | export const ORDER_CLOSE_DELAY = 15 * 60 * 1000; 6 | // 自动完成时间 7 | export const ORDER_COMPLETE_DELAY = 2 * 60 * 60 * 1000; 8 | // 自动取消时间 9 | export const ORDER_CANCEL_DELAY = 2 * 60 * 60 * 1000; 10 | 11 | /** 12 | * 待付款的订单自动关闭 13 | */ 14 | 15 | @Queue() 16 | @Provide() 17 | export class SchoolOrderWaitPayToCloseTask { 18 | @Inject() 19 | schoolOrdersService: SchoolOrdersService; 20 | 21 | async execute(params: { orderNo: string }) { 22 | try { 23 | await this.schoolOrdersService.closeOrder(params.orderNo); 24 | } catch (error) { 25 | console.error(error); 26 | } 27 | } 28 | } 29 | 30 | /** 31 | * 订单自动完成 32 | */ 33 | @Queue() 34 | @Provide() 35 | export class SchoolOrderAutoToCompleteTask { 36 | @Inject() 37 | schoolOrdersService: SchoolOrdersService; 38 | 39 | async execute(params: { orderNo: string }) { 40 | console.info(`[ task ] 订单${params.orderNo} 自动完成 开始...`); 41 | 42 | await this.schoolOrdersService.clickComplete( 43 | params.orderNo, 44 | 'system', 45 | undefined 46 | ); 47 | } 48 | } 49 | 50 | /** 51 | * 超过截止时间未接单自动取消 52 | */ 53 | @Queue() 54 | @Provide() 55 | export class SchoolOrderAutoCancelByDealineTask { 56 | @Inject() 57 | schoolOrdersService: SchoolOrdersService; 58 | async execute(params: { orderNo: string }) { 59 | await this.schoolOrdersService.cancelOrder( 60 | { 61 | orderNo: params.orderNo, 62 | cancelReason: '订单截止时间内未接单,系统自动取消', 63 | }, 64 | 'system', 65 | undefined 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /server/test/controller/api.test.ts: -------------------------------------------------------------------------------- 1 | import { createApp, close, createHttpRequest } from "@midwayjs/mock"; 2 | import { Framework } from "@midwayjs/web"; 3 | import { Application } from "egg"; 4 | 5 | describe("test/controller/api.test.ts", () => { 6 | let app: Application; 7 | 8 | beforeAll(async () => { 9 | // create app 10 | app = await createApp(); 11 | }); 12 | 13 | afterAll(async () => { 14 | await close(app); 15 | }); 16 | 17 | it("should POST /api/get_user", async () => { 18 | // make request 19 | const result = await createHttpRequest(app) 20 | .post("/api/get_user") 21 | .query({ uid: 123 }); 22 | 23 | // use expect by jest 24 | expect(result.status).toBe(200); 25 | expect(result.body.message).toBe("OK"); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /server/test/controller/home.test.ts: -------------------------------------------------------------------------------- 1 | import { createApp, close, createHttpRequest } from '@midwayjs/mock'; 2 | import { Framework } from '@midwayjs/web'; 3 | import { Application } from 'egg'; 4 | import * as assert from 'assert'; 5 | 6 | describe('test/controller/home.test.ts', () => { 7 | 8 | let app: Application; 9 | 10 | beforeAll(async () => { 11 | // create app 12 | app = await createApp(); 13 | }); 14 | 15 | afterAll(async () => { 16 | await close(app); 17 | }); 18 | 19 | it('should GET /', async () => { 20 | // make request 21 | const result = await createHttpRequest(app).get('/'); 22 | 23 | // use expect by jest 24 | expect(result.status).toBe(200); 25 | expect(result.text).toBe('Hello Midwayjs!'); 26 | 27 | // or use assert 28 | assert.deepStrictEqual(result.status, 200); 29 | assert.deepStrictEqual(result.text, 'Hello Midwayjs!'); 30 | }); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "target": "es2018", 5 | "module": "commonjs", 6 | "moduleResolution": "node", 7 | "experimentalDecorators": true, 8 | "emitDecoratorMetadata": true, 9 | "inlineSourceMap":true, 10 | "noImplicitThis": true, 11 | "noUnusedLocals": true, 12 | "stripInternal": true, 13 | "skipLibCheck": true, 14 | "pretty": true, 15 | "declaration": true, 16 | "typeRoots": [ "./typings", "./node_modules/@types"], 17 | "outDir": "dist" 18 | }, 19 | "exclude": [ 20 | "dist", 21 | "node_modules", 22 | "test" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /server/typings/app/index.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper 2 | // Do not modify this file!!!!!!!!! 3 | import 'egg'; 4 | import '@midwayjs/web'; 5 | export * from 'egg'; 6 | export as namespace Egg; -------------------------------------------------------------------------------- /server/typings/config/index.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper 2 | // Do not modify this file!!!!!!!!! 3 | import 'egg'; 4 | import '@midwayjs/web'; 5 | import 'egg-onerror'; 6 | import 'egg-session'; 7 | import 'egg-i18n'; 8 | import 'egg-watcher'; 9 | import 'egg-multipart'; 10 | import 'egg-security'; 11 | import 'egg-development'; 12 | import 'egg-logrotator'; 13 | import 'egg-schedule'; 14 | import 'egg-static'; 15 | import 'egg-jsonp'; 16 | import 'egg-view'; 17 | import { EggPluginItem } from 'egg'; 18 | declare module 'egg' { 19 | interface EggPlugin { 20 | 'onerror'?: EggPluginItem; 21 | 'session'?: EggPluginItem; 22 | 'i18n'?: EggPluginItem; 23 | 'watcher'?: EggPluginItem; 24 | 'multipart'?: EggPluginItem; 25 | 'security'?: EggPluginItem; 26 | 'development'?: EggPluginItem; 27 | 'logrotator'?: EggPluginItem; 28 | 'schedule'?: EggPluginItem; 29 | 'static'?: EggPluginItem; 30 | 'jsonp'?: EggPluginItem; 31 | 'view'?: EggPluginItem; 32 | } 33 | } -------------------------------------------------------------------------------- /server/typings/config/plugin.d.ts: -------------------------------------------------------------------------------- 1 | // This file is created by egg-ts-helper 2 | // Do not modify this file!!!!!!!!! 3 | import 'egg'; 4 | import '@midwayjs/web'; 5 | import 'egg-onerror'; 6 | import 'egg-session'; 7 | import 'egg-i18n'; 8 | import 'egg-watcher'; 9 | import 'egg-multipart'; 10 | import 'egg-security'; 11 | import 'egg-development'; 12 | import 'egg-logrotator'; 13 | import 'egg-schedule'; 14 | import 'egg-static'; 15 | import 'egg-jsonp'; 16 | import 'egg-view'; 17 | import { EggPluginItem } from 'egg'; 18 | declare module 'egg' { 19 | interface EggPlugin { 20 | 'onerror'?: EggPluginItem; 21 | 'session'?: EggPluginItem; 22 | 'i18n'?: EggPluginItem; 23 | 'watcher'?: EggPluginItem; 24 | 'multipart'?: EggPluginItem; 25 | 'security'?: EggPluginItem; 26 | 'development'?: EggPluginItem; 27 | 'logrotator'?: EggPluginItem; 28 | 'schedule'?: EggPluginItem; 29 | 'static'?: EggPluginItem; 30 | 'jsonp'?: EggPluginItem; 31 | 'view'?: EggPluginItem; 32 | } 33 | } --------------------------------------------------------------------------------