commit f28cc3108fbb22b6ce3752eb6a5200a139ca6269 Author: 王文龙 Date: Mon Dec 11 17:29:23 2023 +0800 page Done diff --git a/.eslintignore b/.eslintignore new file mode 100755 index 0000000..8fa9c91 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,8 @@ +/index.html +node_modules +public +dist +shime-uni.d.ts +uni_modules +ua-markdown +src \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100755 index 0000000..96c5cd8 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,10 @@ +module.exports = { + extends: ['@viarotel-org'], + rules: { + 'no-unused-vars': 'off', + 'eqeqeq': 'off', + 'no-undef': 'off', + 'prefer-promise-reject-errors': 'off', + 'antfu/top-level-function': 'off', + }, +} diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..e2b8b92 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.DS_Store +dist +*.local + +# Editor directories and files +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +#user +.hbuilderx +uni-pages.d.ts +pnpm-lock.yaml +yarn.lock +package-lock.json \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100755 index 0000000..aed289f --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +registry=https://registry.npmmirror.com/ +shamefully-hoist=true \ No newline at end of file diff --git a/.yarnrc b/.yarnrc new file mode 100755 index 0000000..87bede5 --- /dev/null +++ b/.yarnrc @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + +registry "https://registry.npmmirror.com/" \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100755 index 0000000..85f33d5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,152 @@ +# Changelog + +## [2.5.5](https://github.com/viarotel-org/vite-uniapp-template/compare/v2.5.4...v2.5.5) (2023-10-18) + + +### Bug Fixes + +* 🚀 修复在 app 端环境下路由插件系统使用异常的问题 ([894ca30](https://github.com/viarotel-org/vite-uniapp-template/commit/894ca308d236fce5846e8348590cfbe1c01838c6)) + +## [2.5.4](https://github.com/viarotel-org/vite-uniapp-template/compare/v2.5.3...v2.5.4) (2023-09-21) + + +### Bug Fixes + +* 🔧 修复小程序端某些样式不生效的问题 ([e532395](https://github.com/viarotel-org/vite-uniapp-template/commit/e5323955809cf57d733064dfa2ebc14cc6f8f37f)) + +## [2.5.3](https://github.com/viarotel-org/vite-uniapp-template/compare/v2.5.2...v2.5.3) (2023-09-14) + + +### Bug Fixes + +* 🐛 修复小程序环境打包失败的问题 ([14c9645](https://github.com/viarotel-org/vite-uniapp-template/commit/14c9645d3c4b3abd248816087b3edd16e9973fc1)) + +## [2.5.2](https://github.com/viarotel-org/vite-uniapp-template/compare/v2.5.1...v2.5.2) (2023-09-09) + + +### Bug Fixes + +* 🔧 修复 uni-network 格式化参数的行为与 axios不一致的问题 ([00af3bf](https://github.com/viarotel-org/vite-uniapp-template/commit/00af3bfc50844ae45d5e860d86bf9aeabf3791d1)) +* 🔧 修复打包后由于方法名混淆导致路由中间件无法匹配触发的问题 ([37515aa](https://github.com/viarotel-org/vite-uniapp-template/commit/37515aa0f526ae3810a979a347cc997443061fe4)) +* 🔧 固定 qs 版本以解决不兼容微信小程序的问题 ([95f733e](https://github.com/viarotel-org/vite-uniapp-template/commit/95f733e8492e13688054739e6144b4fb39544696)) + +## [2.5.1](https://github.com/viarotel-org/vite-uniapp-template/compare/v2.5.0...v2.5.1) (2023-09-09) + + +### Bug Fixes + +* 🗑️ 去除登录页面冗余的空白顶栏 ([25bc3bd](https://github.com/viarotel-org/vite-uniapp-template/commit/25bc3bda88e8da69f8122e7b3e75422560f0b23e)) + +## [2.5.0](https://github.com/viarotel-org/vite-uniapp-template/compare/v2.4.0...v2.5.0) (2023-09-09) + + +### Features + +* 🚀 添加跳转外部网页功能 ([8d062a9](https://github.com/viarotel-org/vite-uniapp-template/commit/8d062a9d86126980181fb6e9ab0ca289f93b8c66)) + +## [2.4.0](https://github.com/viarotel-org/vite-uniapp-template/compare/v2.3.3...v2.4.0) (2023-09-08) + + +### Features + +* 🚀 对部分页面样式进行改进并去除冗余的控制台输出 ([e73ba19](https://github.com/viarotel-org/vite-uniapp-template/commit/e73ba1933c594ecc5e8ad0317d6d35345f9e972f)) + +## [2.3.3](https://github.com/viarotel-org/vite-uniapp-template/compare/v2.3.2...v2.3.3) (2023-09-08) + + +### Bug Fixes + +* 📈 修复入口页面模块引用格式不统一的问题 ([bd72731](https://github.com/viarotel-org/vite-uniapp-template/commit/bd72731cf866940aa4a4e1d84795bc035be05b8c)) + +## [2.3.2](https://github.com/viarotel-org/vite-uniapp-template/compare/v2.3.1...v2.3.2) (2023-09-08) + + +### Bug Fixes + +* 🔧 修复同步脚本错误的问题 ([73d802a](https://github.com/viarotel-org/vite-uniapp-template/commit/73d802abf100f853ae1c1f41a650090a483bfa3c)) + +## [2.3.1](https://github.com/viarotel-org/vite-uniapp-template/compare/v2.3.0...v2.3.1) (2023-09-07) + + +### Bug Fixes + +* 📝 修复文档描述错误 ([3325235](https://github.com/viarotel-org/vite-uniapp-template/commit/3325235dac5f0dac5301cbbafff111c1509548de)) + +## [2.3.0](https://github.com/viarotel-org/vite-uniapp-template/compare/v2.2.1...v2.3.0) (2023-09-05) + + +### Features + +* 🎨 主题色定制相关配置功能更新 ([bcadbfa](https://github.com/viarotel-org/vite-uniapp-template/commit/bcadbfaf583a283804bd1ebdd6b5846ae11f0fb0)) + +## [2.2.1](https://github.com/viarotel-org/vite-uniapp-template/compare/v2.2.0...v2.2.1) (2023-09-01) + + +### Bug Fixes + +* 🔧 修复使用 yarn 作为包管理器时启动项目报错的问题 ([1778bb9](https://github.com/viarotel-org/vite-uniapp-template/commit/1778bb9c4b56e097ba5cadc1ae6e37fd89357ca8)) + +## [2.2.0](https://github.com/viarotel-org/vite-uniapp-template/compare/v2.1.1...v2.2.0) (2023-08-29) + + +### Features + +* 🚀 登录示例页面调整 ([a0c1688](https://github.com/viarotel-org/vite-uniapp-template/commit/a0c16881e36e836ee7d9215dfec4615e1984a2bb)) + +## [2.1.1](https://github.com/viarotel-org/vite-uniapp-template/compare/v2.1.0...v2.1.1) (2023-08-29) + + +### Bug Fixes + +* bugfix ([9757722](https://github.com/viarotel-org/vite-uniapp-template/commit/97577229d7999f10a9efdcb3ef08efa8a3328cde)) + + +### Performance Improvements + +* 🚀 去除冗余的默认导出以降低生产包大小 ([88a529a](https://github.com/viarotel-org/vite-uniapp-template/commit/88a529a51541210c6a030fbb56ebc044173c0c28)) + +## [2.1.0](https://github.com/viarotel-org/vite-uniapp-template/compare/v2.0.1...v2.1.0) (2023-08-28) + + +### Miscellaneous Chores + +* release 2.1.0 ([ccc4cb1](https://github.com/viarotel-org/vite-uniapp-template/commit/ccc4cb19295420b632f61ae4e5424809e55dc7b8)) + +## [2.0.1](https://github.com/viarotel-org/vite-uniapp-template/compare/v2.0.0...v2.0.1) (2023-08-14) + + +### Performance Improvements + +* 🔧 调整路由导出方式以简化路由中间件定义方式 ([d0f9015](https://github.com/viarotel-org/vite-uniapp-template/commit/d0f901526adeed8ab60898a18d5ade046f14ceeb)) + +## [2.0.0](https://github.com/viarotel-org/vite-uniapp-template/compare/v2.0.0...v2.0.0) (2023-08-09) + + +### Features + +* ✨ 样式优化及调整 ([c3d4a56](https://github.com/viarotel-org/vite-uniapp-template/commit/c3d4a56e836f4af4cc1d929d16f9b46319c69617)) +* feat ([19894dc](https://github.com/viarotel-org/vite-uniapp-template/commit/19894dcbd075ba5181372df19c4e6c2387afa120)) + + +### Bug Fixes + +* :bug: bugfix ([2bf4391](https://github.com/viarotel-org/vite-uniapp-template/commit/2bf4391b96bd0b2e94acfcf7ee36a757d02808aa)) +* :bug: 修复 uni-vite-plugin-h5-prod-effect 导致 h5 打包后无法正常运行的问题 ([cfe09f6](https://github.com/viarotel-org/vite-uniapp-template/commit/cfe09f65eecc4d9e1f7867a4280e2a54feb10158)) +* 🐛 bugfix ([deaa1ec](https://github.com/viarotel-org/vite-uniapp-template/commit/deaa1ec2f283d9d54eb63e852ae1e30edb454dc1)) +* 📝 bugfix ([91ed0eb](https://github.com/viarotel-org/vite-uniapp-template/commit/91ed0eb09ee84dd62769a00293667ea9d6ce5622)) +* 📝 修复路由文件缺失导致报错的问题 ([4d51094](https://github.com/viarotel-org/vite-uniapp-template/commit/4d5109473f16c24530b797cd9aa6e48f36d862e9)) + +### Performance Improvements + +* :ambulance: 减少生产环境下包大小 ([e1b67c6](https://github.com/viarotel-org/vite-uniapp-template/commit/e1b67c6fff1a2add11f498a0eba7bff70f794e4c)) +* :memo: ([dd8dcf5](https://github.com/viarotel-org/vite-uniapp-template/commit/dd8dcf598dec5721e27c3e953535f33af1a627c1)) +* 🎉 路由相关代码逻辑优化 ([101f828](https://github.com/viarotel-org/vite-uniapp-template/commit/101f828fcfdc8cdb04e29f6320d775fe84a2bfac)) +* 📝 去除冗余代码 ([6cc02e9](https://github.com/viarotel-org/vite-uniapp-template/commit/6cc02e9baa3933695215a11457253b9cdcf2e2bd)) +* 📝 去除冗余依赖 ([c98f33e](https://github.com/viarotel-org/vite-uniapp-template/commit/c98f33ef7e897640fa0b08fd1fda9dc9d5ed61e1)) +* perf ([a48a7fc](https://github.com/viarotel-org/vite-uniapp-template/commit/a48a7fc7875f81a1e4d299004c69b7dafde29b99)) +* 图标组件性能优化 ([1d2d89d](https://github.com/viarotel-org/vite-uniapp-template/commit/1d2d89d3708a72989a7fb4795a7c10d4ea076987)) + + +### Miscellaneous Chores + +* release 2.0.0 ([9990344](https://github.com/viarotel-org/vite-uniapp-template/commit/9990344751ab75dc77d2a1d7b00873b02148e656)) diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..c396424 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 viarotel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100755 index 0000000..2b6bded --- /dev/null +++ b/README.md @@ -0,0 +1,274 @@ +## 特点 + +- 💪 Assets: 提供了全局静态资源加载工具,无感切换加载本地静态资源/远程静态资源,解决小程序环境下包大小限制问题。 +- 📦 SubPackages: 符合心智模型的分包风格,合理的 pages 目录结构,与分包配置轻松实现功能分包。 +- 🛣 Router: 使用 [uniapp-router-next](https://gitee.com/wen-jason/uni-router/tree/main/packages/uniapp-router-next),并通过优化封装,API 同 VueRouter 类似,扩展了拦截器、中间件、路由别名功能。 +- 📊 Store: 使用 [Pinia](https://pinia.vuejs.org/zh/) 强力驱动,轻松实现应用状态管理。 +- ⚡️ Request: 请求库使用 [uni-network](https://github.com/uni-helper/uni-network) 完全基于 uniapp API 编写的高性能请求库, API 同 axios。 +- 👇 Z-paging: 内置了高性能且易于使用的业务常用下拉分页组件模块,轻松实现下拉刷新、上拉加载等功能。 +- 💅 Unocss: 使用原子化 CSS 引擎,小程序环境下依然完美支持原子化的 class 命名书写规则。 +- 🎨 UI-libs: 预设了 [uivew-plus](https://uiadmin.net/uview-plus/) 和 [uni-ui](https://uniapp.dcloud.net.cn/component/uniui/uni-ui.html) 两者相辅相成,轻松满足绝大多数业务场景,并支持主题色定制功能。 +- 📝 NoTs: 只使用 JavaScript,在常规业务场景或人员水平差距过大情况下,TypeScript 并不会提升开发体验。 + +## 使用方法 + +### 安装项目依赖 + +> 打开并进入克隆的项目根目录下执行以下命令 +> 以下命令推荐 使用 pnpm 进行操作 不过你依然可以使用 npm/yarn + +```shell +pnpm install +``` + +### 运行项目 + +#### 任意编辑器直接运行本项目 + +```shell +# h5端 +pnpm dev:h5 +# 微信小程序端 +pnpm dev:mp-weixin +# 安卓端 +pnpm dev:app-android +#... 更多端请参阅 package.json/script +``` + +#### 在 HBuilder 中运行本项目 + +1. 将项目拖动到 HBuilder 中 +2. 使用 pnpm install 安装好依赖 +3. 点击项目 /src 目录中的任意文件 +4. 点击编辑器上方点击运行选择需要运行的环境 + +### 功能示例 + +#### 静态资源处理 + +```js +// 使用远程静态资源 +import { useAssets } from './utils/assets/remote' + +// 使用本地静态资源 +import { useAssets } from './utils/assets/local' + +// 全局挂载 +app.config.globalProperties.$assets = useAssets + +// template中使用 +// +``` + +#### 全局主题色定制 + +> 由 [unocss-preset-shades](https://github.com/viarotel-org/packages/tree/main/packages/unocss-preset-shades#readme) 提供支持 + +```html + +
+ +
+ +
+ +``` + +#### 路由间功能跳转 + +```js +// 跳转页面 +const methods = { + routerDemo() { + this.$Router.push({ + path: '/login', + query: { + id: 'id' + } + }) + // 获取页面参数 + this.$Route.query.id + + // 关闭当前页面跳转到某个页面 + this.$Router.replace('/login') + // 关闭所有打开的页面跳转到某个页面 + this.$Router.replaceAll('/login') + } +} + +// 为路由设置别名 +// pages.config.js 中 +const aliasConfig = { + path: 'pages/login/index', + // 通过添加 aliasPath 字段 + aliasPath: '/login' +} +``` + +#### 使用路由守卫 + +> 位于 router/guards 中 + +```js +import store from '@/store/index.js' + +const homePath = '/pages/index/index' +const loginPath = '/pages/login/index' + +const whiteList = [loginPath] + +export default (router) => { + const userStore = store.useUserStore() + + const loginRoute = (to) => ({ + path: loginPath, + navType: 'reLaunch', + force: true, + query: { + redirect: { + path: to.path, + query: to.query + } + } + }) + + router.beforeEach((to, from, next) => { + // console.log('permission.beforeEach.to', to) + // console.log('permission.beforeEach.from', from) + + const token = userStore.token + const userId = userStore.userId + + console.log('token', token) + console.log('userId', userId) + + if (token) { + if (to.path === loginPath) { + next(homePath) + } else if (userId) { + next() + } else { + userStore + .getUserInfo() + .then(() => { + next() + }) + .catch((error) => { + console.warn(error) + userStore.logout({ silenced: true }) + next(loginRoute(to)) + }) + } + } else if (whiteList.includes(to.path)) { + next() + } else { + next(loginRoute(to)) + } + }) + + router.afterEach(() => {}) +} +``` + +#### 使用基于路由的中间件 + +> pages.config.js 中 + +```js +// 使用名为 realname 的中间件 +const pageConfig = { + path: '/pages/personal/index', + aliasPath: '/personal', + meta: { + middleware: ['realname'] + } +} +``` + +定义中间件 + +> router/guards/index.js 中 + +```js +// 使用 defineMiddleware 定义并包装为中间件 +import realname from './realname/index.js' +import { defineMiddleware } from '$uni-router/middleware' + +export default (app, router) => { + // 使用 defineMiddleware 定义了路由中间件 + defineMiddleware(realname, { router, app }) +} +``` + +编写路由中间件代码 + +> router/guards/realname/index.js 中 + +```js +import store from '@/store/index.js' +import { useDialog, useToast } from '@/utils/modals' + +export default (router) => { + const userStore = store.useUserStore() + + router.beforeEach((to, from, next) => { + console.log('realname.beforeEach.to', to) + console.log('realname.beforeEach.from', from) + + const realStatus = userStore.userInfo.realStatus + + switch (realStatus) { + case 3: + next() + break + case 2: + useToast('实名审核中, 请稍后再试').then(() => { + next(false) + }) + break + case 4: + useDialog(`${userStore.userInfo.auditResult || '提交的实名信息不符'}`, { + title: '实名失败', + showCancelButton: true, + confirmText: '重新认证' + }) + .then(() => { + next({ path: '/pages/realname/index' }) + }) + .catch(() => { + next(false) + }) + break + default: + useDialog('请先进行实名认证', { showCancelButton: true }) + .then(() => { + next({ path: '/pages/realname/index' }) + }) + .catch(() => { + next(false) + }) + break + } + }) + // router.afterEach(() => {}) +} +``` + +### 主要使用的包 + +- vitejs +- uniapp +- pinia +- uview-plus +- uni-ui +- @uni-helper/uni-network +- uniapp-router-next +- z-paging +- unocss +- unocss-applet + +### 常见问题 + +#### 无法正常安装依赖/无法启动 + +删除 pnpm-lock.yaml / yarn.lock / package-lock.json 文件后重新安装依赖 diff --git a/auto-imports.d.ts b/auto-imports.d.ts new file mode 100644 index 0000000..d298c3c --- /dev/null +++ b/auto-imports.d.ts @@ -0,0 +1,66 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// noinspection JSUnusedGlobalSymbols +// Generated by unplugin-auto-import +export {} +declare global { + const EffectScope: typeof import('vue')['EffectScope'] + const computed: typeof import('vue')['computed'] + const createApp: typeof import('vue')['createApp'] + const customRef: typeof import('vue')['customRef'] + const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] + const defineComponent: typeof import('vue')['defineComponent'] + const effectScope: typeof import('vue')['effectScope'] + const getCurrentInstance: typeof import('vue')['getCurrentInstance'] + const getCurrentScope: typeof import('vue')['getCurrentScope'] + const h: typeof import('vue')['h'] + const inject: typeof import('vue')['inject'] + const isProxy: typeof import('vue')['isProxy'] + const isReactive: typeof import('vue')['isReactive'] + const isReadonly: typeof import('vue')['isReadonly'] + const isRef: typeof import('vue')['isRef'] + const markRaw: typeof import('vue')['markRaw'] + const nextTick: typeof import('vue')['nextTick'] + const onActivated: typeof import('vue')['onActivated'] + const onBeforeMount: typeof import('vue')['onBeforeMount'] + const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] + const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] + const onDeactivated: typeof import('vue')['onDeactivated'] + const onErrorCaptured: typeof import('vue')['onErrorCaptured'] + const onMounted: typeof import('vue')['onMounted'] + const onRenderTracked: typeof import('vue')['onRenderTracked'] + const onRenderTriggered: typeof import('vue')['onRenderTriggered'] + const onScopeDispose: typeof import('vue')['onScopeDispose'] + const onServerPrefetch: typeof import('vue')['onServerPrefetch'] + const onUnmounted: typeof import('vue')['onUnmounted'] + const onUpdated: typeof import('vue')['onUpdated'] + const provide: typeof import('vue')['provide'] + const reactive: typeof import('vue')['reactive'] + const readonly: typeof import('vue')['readonly'] + const ref: typeof import('vue')['ref'] + const resolveComponent: typeof import('vue')['resolveComponent'] + const shallowReactive: typeof import('vue')['shallowReactive'] + const shallowReadonly: typeof import('vue')['shallowReadonly'] + const shallowRef: typeof import('vue')['shallowRef'] + const toRaw: typeof import('vue')['toRaw'] + const toRef: typeof import('vue')['toRef'] + const toRefs: typeof import('vue')['toRefs'] + const toValue: typeof import('vue')['toValue'] + const triggerRef: typeof import('vue')['triggerRef'] + const unref: typeof import('vue')['unref'] + const useAttrs: typeof import('vue')['useAttrs'] + const useCssModule: typeof import('vue')['useCssModule'] + const useCssVars: typeof import('vue')['useCssVars'] + const useSlots: typeof import('vue')['useSlots'] + const watch: typeof import('vue')['watch'] + const watchEffect: typeof import('vue')['watchEffect'] + const watchPostEffect: typeof import('vue')['watchPostEffect'] + const watchSyncEffect: typeof import('vue')['watchSyncEffect'] +} +// for type re-export +declare global { + // @ts-ignore + export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue' + import('vue') +} diff --git a/index.html b/index.html new file mode 100755 index 0000000..42b27e8 --- /dev/null +++ b/index.html @@ -0,0 +1,24 @@ + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/jsconfig.json b/jsconfig.json new file mode 100755 index 0000000..ecc94c6 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,12 @@ +{ + "exclude": ["node_modules", "dist"], + "include": ["src/**/*"], + "compilerOptions": { + "baseUrl": ".", + "lib": ["ESNext", "DOM"], + "paths": { + "@/*": ["src/*"] + }, + "types": ["@dcloudio/types", "miniprogram-api-typings", "mini-types"] + }, +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100755 index 0000000..c8dbfb8 --- /dev/null +++ b/package.json @@ -0,0 +1,100 @@ +{ + "name": "escort", + "version": "1.0.0", + "scripts": { + "lint": "pnpm lint:js", + "lint:js": "eslint . --ext .vue,.js,.ts,.jsx,.tsx,.md --ignore-path .eslintignore --fix", + "dev:app": "uni -p app", + "dev:app-android": "uni -p app-android", + "dev:app-ios": "uni -p app-ios", + "dev:custom": "uni -p", + "dev:h5": "uni", + "dev:h5:ssr": "uni --ssr", + "dev:mp-alipay": "uni -p mp-alipay", + "dev:mp-baidu": "uni -p mp-baidu", + "dev:mp-jd": "uni -p mp-jd", + "dev:mp-kuaishou": "uni -p mp-kuaishou", + "dev:mp-lark": "uni -p mp-lark", + "dev:mp-qq": "uni -p mp-qq", + "dev:mp-toutiao": "uni -p mp-toutiao", + "dev": "uni -p mp-weixin", + "dev:quickapp-webview": "uni -p quickapp-webview", + "dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei", + "dev:quickapp-webview-union": "uni -p quickapp-webview-union", + "build:app": "uni build -p app", + "build:app-android": "uni build -p app-android", + "build:app-ios": "uni build -p app-ios", + "build:custom": "uni build -p", + "build:h5": "uni build", + "build:h5:ssr": "uni build --ssr", + "build:mp-alipay": "uni build -p mp-alipay", + "build:mp-baidu": "uni build -p mp-baidu", + "build:mp-jd": "uni build -p mp-jd", + "build:mp-kuaishou": "uni build -p mp-kuaishou", + "build:mp-lark": "uni build -p mp-lark", + "build:mp-qq": "uni build -p mp-qq", + "build:mp-toutiao": "uni build -p mp-toutiao", + "build:mp-weixin": "uni build -p mp-weixin", + "build:quickapp-webview": "uni build -p quickapp-webview", + "build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei", + "build:quickapp-webview-union": "uni build -p quickapp-webview-union" + }, + "dependencies": { + "@dcloudio/uni-app": "3.0.0-3090820231124001", + "@dcloudio/uni-app-plus": "3.0.0-3090820231124001", + "@dcloudio/uni-components": "3.0.0-3090820231124001", + "@dcloudio/uni-h5": "3.0.0-3090820231124001", + "@dcloudio/uni-mp-alipay": "3.0.0-3090820231124001", + "@dcloudio/uni-mp-baidu": "3.0.0-3090820231124001", + "@dcloudio/uni-mp-jd": "3.0.0-3090820231124001", + "@dcloudio/uni-mp-kuaishou": "3.0.0-3090820231124001", + "@dcloudio/uni-mp-lark": "3.0.0-3090820231124001", + "@dcloudio/uni-mp-qq": "3.0.0-3090820231124001", + "@dcloudio/uni-mp-toutiao": "3.0.0-3090820231124001", + "@dcloudio/uni-mp-weixin": "3.0.0-3090820231124001", + "@dcloudio/uni-mp-xhs": "3.0.0-3090820231124001", + "@dcloudio/uni-quickapp-webview": "3.0.0-3090820231124001", + "@dcloudio/uni-ui": "^1.4.28", + "@uni-helper/uni-env": "^0.0.3", + "@uni-helper/uni-network": "^0.16.1", + "@uni-helper/uni-promises": "^0.2.0", + "@viarotel-org/unocss-preset-shades": "^0.7.0", + "color": "^4.2.3", + "dayjs": "^1.11.9", + "js-cookie": "^3.0.5", + "lodash-es": "^4.17.21", + "pinia": "2.0.33", + "qs": "6.9.7", + "uniapp-router-next": "^1.2.4", + "uview-plus": "^3.1.41", + "vue": "3.2.47", + "vue-i18n": "^9.1.9", + "z-paging": "^2.5.8" + }, + "devDependencies": { + "@dcloudio/types": "^3.3.2", + "@dcloudio/uni-automator": "3.0.0-3090820231124001", + "@dcloudio/uni-cli-shared": "3.0.0-3090820231124001", + "@dcloudio/uni-stacktracey": "3.0.0-3090820231124001", + "@dcloudio/vite-plugin-uni": "3.0.0-3090820231124001", + "@uni-helper/vite-plugin-uni-pages": "^0.2.9", + "@unocss/transformer-directives": "0.55.3", + "@viarotel-org/eslint-config": "^0.7.0", + "@vue/runtime-core": "^3.2.45", + "eslint": "^8.48.0", + "mini-types": "^0.1.7", + "miniprogram-api-typings": "^3.10.0", + "postcss": "^8.4.24", + "postcss-import": "^15.1.0", + "postcss-nested": "^6.0.1", + "postcss-remove-inline-comments": "^0.0.2", + "postcss-scss": "^4.0.6", + "sass": "^1.63.4", + "typescript": "5.1.6", + "unocss": "0.55.3", + "unocss-applet": "0.5.5", + "unplugin-auto-import": "^0.17.2", + "vite": "4.0.3", + "vite-plugin-eslint": "^1.8.1" + } +} diff --git a/pages.config.js b/pages.config.js new file mode 100755 index 0000000..f1de649 --- /dev/null +++ b/pages.config.js @@ -0,0 +1,221 @@ +import { defineUniPages } from '@uni-helper/vite-plugin-uni-pages' + +export default defineUniPages({ + easycom: { + autoscan: true, + custom: { + '^u-(.*)': 'uview-plus/components/u-$1/u-$1.vue', + '^uni-(.*)': '@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue', + '^(?!z-paging-refresh|z-paging-load-more)z-paging(.*)': + 'z-paging/components/z-paging$1/z-paging$1.vue', + }, + }, + pages: [ + { + path: 'pages/index/home/index', + aliasPath: '/', + meta: { + key: 'home', + }, + style: { + navigationBarTitleText: '', + }, + }, + { + path: 'pages/index/order/index', + aliasPath: '/order', + meta: { + key: 'order', + }, + style: { + navigationBarTitleText: '订单', + }, + }, + { + path: 'pages/index/personal/index', + aliasPath: '/personal', + meta: { + key: 'personal', + }, + style: { + navigationBarTitleText: '我的', + }, + }, + { + path: 'pages/login/index', + aliasPath: '/login', + style: { + // navigationStyle: 'custom', + navigationBarTitleText: '登录', + }, + }, + { + path: 'pages/errors/404/index', + aliasPath: '/404', + style: { + navigationBarTitleText: '404', + }, + }, + ], + subPackages: [ + { + root: 'pages/webview', + pages: [ + { + path: 'index', + aliasPath: '/webview', + style: { + navigationBarTitleText: 'webview', + }, + }, + ], + }, + { + root: 'pages/form', + pages: [ + { + path: 'index', + aliasPath: '/form', + style: { + navigationBarTitleText: '填写订单', + }, + }, + { + path: 'complete', + aliasPath: '/complete', + style: { + navigationBarTitleText: '订单完成', + }, + }, + ], + }, + { + root: 'pages/other', + pages: [ + { + path: 'income-details', + aliasPath: '/income-details', + style: { + navigationBarTitleText: '收入详情', + }, + }, + { + path: 'edit-userinfo', + aliasPath: '/edit-userinfo', + style: { + navigationBarTitleText: '编辑资料', + }, + }, + { + path: 'switch', + aliasPath: '/switch', + style: { + navigationBarTitleText: '成为陪诊师', + }, + }, + ], + }, + // { + // root: 'pages/middleware', + // pages: [ + // { + // path: 'index', + // aliasPath: '/middleware', + // meta: { + // middleware: ['realname'], + // }, + // style: { + // navigationBarTitleText: '路由中间件', + // }, + // }, + // ], + // }, + { + root: 'pages/statement', + pages: [ + { + path: 'index', + aliasPath: '/statement', + style: { + navigationBarTitleText: '产品服务协议', + }, + }, + ], + }, + { + root: 'pages/realname', + pages: [ + { + path: 'index', + aliasPath: '/realname', + style: { + navigationBarTitleText: '实名认证', + }, + }, + ], + }, + { + root: 'pages/contact', + pages: [ + { + path: 'index', + aliasPath: '/contact', + style: { + navigationBarTitleText: '联系我们', + }, + }, + ], + }, + ], + tabBar: { + // color: '#999999', + // selectedColor: '#018d71', + // backgroundColor: '#F8F8F8', + list: [ + { + // iconPath: 'static/tabbar/tab-home.png', + // selectedIconPath: 'static/tabbar/tab-home-active.png', + pagePath: 'pages/index/home/index', + // text: '主页', + }, + { + // iconPath: 'static/tabbar/tab-example.png', + // selectedIconPath: 'static/tabbar/tab-example-active.png', + pagePath: 'pages/index/order/index', + // text: '示例', + }, + { + // iconPath: 'static/tabbar/tab-personal.png', + // selectedIconPath: 'static/tabbar/tab-personal-active.png', + pagePath: 'pages/index/personal/index', + // text: '我的', + }, + ], + }, + globalStyle: { + navigationBarTextStyle: 'white', + navigationBarTitleText: '', + navigationBarBackgroundColor: '#FF8CA6', + backgroundColor: '#ffffff', + // navigationStyle: "custom", + "usingComponents": { + // "van-cell": "/wxcomponents/vant-weapp/cell", + // "van-checkbox": "/wxcomponents/vant-weapp/checkbox", + // "van-cell-group": "/wxcomponents/vant-weapp/cell-group", + // "van-checkbox-group": "/wxcomponents/vant-weapp/checkbox-group", + "van-rate": "/wxcomponents/vant-weapp/rate", + "van-icon": "/wxcomponents/vant-weapp/icon" + // "van-tabbar": "/wxcomponents/@vant/weapp/tabbar/index", + // "van-tabbar-item": "/wxcomponents/@vant/weapp/tabbar-item/index" + } + }, + // condition: { + // current: 0, + // list: [ + // { + // name: 'pages/contact/index', + // path: 'pages/contact/index', + // }, + // ], + // }, +}) diff --git a/postcss.config.js b/postcss.config.js new file mode 100755 index 0000000..8623638 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,8 @@ +import nested from 'postcss-nested' +import removeInlineComments from 'postcss-remove-inline-comments' +import postcssScss from 'postcss-scss' + +export default { + parser: postcssScss, + plugins: [removeInlineComments, nested], +} diff --git a/src/App.vue b/src/App.vue new file mode 100755 index 0000000..698a577 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,23 @@ + + + diff --git a/src/api/base/index.js b/src/api/base/index.js new file mode 100755 index 0000000..0d02036 --- /dev/null +++ b/src/api/base/index.js @@ -0,0 +1,76 @@ +import request from '@/utils/request/index.js' +import { baseURL, responseSuccessCode } from '@/configs/request.js' + +/** + * @description 模拟接口 + * @param mockData 想要返回的模拟数据 + */ + +export function mock ({ mockData = {}, delay = 500 } = {}) { + return new Promise((resolve) => { + setTimeout(() => { + resolve({ + code: responseSuccessCode, + success: true, + data: mockData, + }) + }, delay) + }) +} + +/** + * @desc 获取基础地址 + */ +export const getBaseURL = () => baseURL + +/** + * 获取字典数据 + */ +export function getDictList (dictType) { + return mock({ + dictType, + mockData: [], + }) +} + +/** + * @desc 获取上传地址 + */ +export const getUploadURL = () => `${baseURL}/oss/upload` + +/** + * @desc 下载文件 + */ +export function downloadFile (id) { + return window.open(`${baseURL}/downloadFile?id=${id}`) +} + +/** + * @desc 获取站点配置 + */ +export const getSiteConfig = () => mock({ mockData: {} }) + +/** + * @desc 上传文件 + */ +export const uploadFile = params => + request.upload({ + url: '/oss/upload', + dataType: 'json', + headers: { + 'content-type': 'multipart/form-data', + }, + ...(params || {}), + }) + +/** + * @desc 服务项目列表 +*/ +export const fetchPzServerList = params => + request.get('/pzserver/list', params) + +/** + * @desc 医院列表 +*/ +export const fetchPzHospitalList = params => + request.get('/pzhospital/list', params) \ No newline at end of file diff --git a/src/api/home/index.js b/src/api/home/index.js new file mode 100755 index 0000000..d9f735f --- /dev/null +++ b/src/api/home/index.js @@ -0,0 +1,2 @@ +// import request from '@/utils/request/index.js' +// import { mock } from '../base/index.js' diff --git a/src/api/index.js b/src/api/index.js new file mode 100755 index 0000000..fa52519 --- /dev/null +++ b/src/api/index.js @@ -0,0 +1,17 @@ +import * as base from './base/index.js' +import * as user from './user/index.js' +import * as home from './home/index.js' +import * as realname from './realname/index.js' + +const api = { + ...base, + ...user, + ...home, + ...realname, +} + +export default { + install(app) { + app.config.globalProperties.$api = api + }, +} diff --git a/src/api/realname/index.js b/src/api/realname/index.js new file mode 100755 index 0000000..64f4fe0 --- /dev/null +++ b/src/api/realname/index.js @@ -0,0 +1,27 @@ +// import request from '@/utils/request/index.js' +import { mock } from '../base/index.js' + +/** + * 获取手机号 + */ +export const phoneNumber = data => mock(data) + +/** + * 获取可供选择的户籍地区 + */ +export const wxdepartTree = data => mock(data) + +/** + * 验证用户信息在数据库中是否已存在 + */ +export const checkUserinfo = data => mock({ ...data, mockData: true }) + +/** + * 数据库中已存在 直接绑定该用户 + */ +export const bindUserinfo = data => mock({ ...data, mockData: true }) + +/** + * 数据库中不存在 提交实名认证信息 + */ +export const wxrealnameAuth = data => mock(data) diff --git a/src/api/user/index.js b/src/api/user/index.js new file mode 100755 index 0000000..9d6812f --- /dev/null +++ b/src/api/user/index.js @@ -0,0 +1,62 @@ +import { mock } from '../base/index.js' +import request from '@/utils/request/index.js' + +/** + * @description 用户登录 + */ +export const userLogin = data => + // mock({ ...data, mockData: { token: 'mock-token' } }) + request.post('/wxlogin', data) +/** + * @description 保存用户信息 + */ +export const userSave = data => + request.post('/register', data) + +/** + * @description 获取当前登录用户手机号 + */ +export const getPhone = params => + // mock({ ...data, mockData: { token: 'mock-token' } }) + request.get('/getPhone', params) + +/** + * @description 获取当前登录用户信息 + */ +export const getUser = params => + // mock({ ...data, mockData: { token: 'mock-token' } }) + request.get('/wxUser/info', params) + +/** + * @description 获取当前登录用户信息 + * @param realStatus 1-未实名 2-实名中 3--已经实名 4-实名失败 + */ +export const getUserInfo = data => + mock({ + ...data, + mockData: { + id: 'mock-id', + username: 'viarotel', + realStatus: '1', + }, + }) + +/** + * @description 获取当前登录用户菜单 + */ +export const getUserMenus = data => mock({ ...data, mockData: [] }) + +/** + * @description 用户修改密码 + */ +export const updatePassword = data => mock(data) + +/** + * @description 上传用户头像 + */ +export const userHeadimg = data => mock(data) + +/** + * @description 退出登录 + */ +export const logout = () => mock() diff --git a/src/assets/avatar.gif b/src/assets/avatar.gif new file mode 100755 index 0000000..7808220 Binary files /dev/null and b/src/assets/avatar.gif differ diff --git a/src/assets/fan.png b/src/assets/fan.png new file mode 100755 index 0000000..6eccf89 Binary files /dev/null and b/src/assets/fan.png differ diff --git a/src/assets/home-icon/h-icon-1.png b/src/assets/home-icon/h-icon-1.png new file mode 100755 index 0000000..688637e Binary files /dev/null and b/src/assets/home-icon/h-icon-1.png differ diff --git a/src/assets/home-icon/h-icon-2.png b/src/assets/home-icon/h-icon-2.png new file mode 100755 index 0000000..2d2cd0e Binary files /dev/null and b/src/assets/home-icon/h-icon-2.png differ diff --git a/src/assets/home-icon/h-icon-3.png b/src/assets/home-icon/h-icon-3.png new file mode 100755 index 0000000..b5b98d9 Binary files /dev/null and b/src/assets/home-icon/h-icon-3.png differ diff --git a/src/assets/home-icon/h-icon-4.png b/src/assets/home-icon/h-icon-4.png new file mode 100755 index 0000000..81e3855 Binary files /dev/null and b/src/assets/home-icon/h-icon-4.png differ diff --git a/src/assets/home-icon/h-icon-5.png b/src/assets/home-icon/h-icon-5.png new file mode 100755 index 0000000..fb7c2f9 Binary files /dev/null and b/src/assets/home-icon/h-icon-5.png differ diff --git a/src/assets/home-icon/h-icon-6.png b/src/assets/home-icon/h-icon-6.png new file mode 100755 index 0000000..d488af7 Binary files /dev/null and b/src/assets/home-icon/h-icon-6.png differ diff --git a/src/assets/home-icon/h-icon-7.png b/src/assets/home-icon/h-icon-7.png new file mode 100755 index 0000000..c92fa8c Binary files /dev/null and b/src/assets/home-icon/h-icon-7.png differ diff --git a/src/assets/home-icon/h-icon-8.png b/src/assets/home-icon/h-icon-8.png new file mode 100755 index 0000000..9d09b96 Binary files /dev/null and b/src/assets/home-icon/h-icon-8.png differ diff --git a/src/assets/image-wechat.png b/src/assets/image-wechat.png new file mode 100755 index 0000000..3dc350c Binary files /dev/null and b/src/assets/image-wechat.png differ diff --git a/src/assets/images/contact/bg-tel.jpg b/src/assets/images/contact/bg-tel.jpg new file mode 100755 index 0000000..1f96917 Binary files /dev/null and b/src/assets/images/contact/bg-tel.jpg differ diff --git a/src/assets/images/realname/bg-certificate-badge.png b/src/assets/images/realname/bg-certificate-badge.png new file mode 100755 index 0000000..7d19d52 Binary files /dev/null and b/src/assets/images/realname/bg-certificate-badge.png differ diff --git a/src/assets/images/realname/bg-certificate-portrait.png b/src/assets/images/realname/bg-certificate-portrait.png new file mode 100755 index 0000000..73e52e4 Binary files /dev/null and b/src/assets/images/realname/bg-certificate-portrait.png differ diff --git a/src/assets/images/realname/icon-camera.png b/src/assets/images/realname/icon-camera.png new file mode 100755 index 0000000..326cb4c Binary files /dev/null and b/src/assets/images/realname/icon-camera.png differ diff --git a/src/assets/kefu.png b/src/assets/kefu.png new file mode 100755 index 0000000..98aeb19 Binary files /dev/null and b/src/assets/kefu.png differ diff --git a/src/assets/order-bg.png b/src/assets/order-bg.png new file mode 100644 index 0000000..d476824 Binary files /dev/null and b/src/assets/order-bg.png differ diff --git a/src/assets/personal/edit.jpg b/src/assets/personal/edit.jpg new file mode 100644 index 0000000..0339aa1 Binary files /dev/null and b/src/assets/personal/edit.jpg differ diff --git a/src/assets/personal/guanyu.png b/src/assets/personal/guanyu.png new file mode 100755 index 0000000..cd0e1a2 Binary files /dev/null and b/src/assets/personal/guanyu.png differ diff --git a/src/assets/personal/lianxi.png b/src/assets/personal/lianxi.png new file mode 100755 index 0000000..2e1d800 Binary files /dev/null and b/src/assets/personal/lianxi.png differ diff --git a/src/assets/personal/person.png b/src/assets/personal/person.png new file mode 100644 index 0000000..83b97d3 Binary files /dev/null and b/src/assets/personal/person.png differ diff --git a/src/assets/personal/qiehuan.png b/src/assets/personal/qiehuan.png new file mode 100755 index 0000000..12bef97 Binary files /dev/null and b/src/assets/personal/qiehuan.png differ diff --git a/src/assets/personal/shouru.png b/src/assets/personal/shouru.png new file mode 100755 index 0000000..6fd9ec8 Binary files /dev/null and b/src/assets/personal/shouru.png differ diff --git a/src/assets/personal/wenti.jpg b/src/assets/personal/wenti.jpg new file mode 100644 index 0000000..5869e2e Binary files /dev/null and b/src/assets/personal/wenti.jpg differ diff --git a/src/assets/sou.png b/src/assets/sou.png new file mode 100755 index 0000000..6c36ce8 Binary files /dev/null and b/src/assets/sou.png differ diff --git a/src/assets/step-active.png b/src/assets/step-active.png new file mode 100755 index 0000000..511f03a Binary files /dev/null and b/src/assets/step-active.png differ diff --git a/src/assets/step.png b/src/assets/step.png new file mode 100755 index 0000000..bb4002f Binary files /dev/null and b/src/assets/step.png differ diff --git a/src/assets/tabbar/home-sel.png b/src/assets/tabbar/home-sel.png new file mode 100755 index 0000000..113c357 Binary files /dev/null and b/src/assets/tabbar/home-sel.png differ diff --git a/src/assets/tabbar/home.png b/src/assets/tabbar/home.png new file mode 100755 index 0000000..cc2b20c Binary files /dev/null and b/src/assets/tabbar/home.png differ diff --git a/src/assets/tabbar/my-sel.png b/src/assets/tabbar/my-sel.png new file mode 100755 index 0000000..4558fbb Binary files /dev/null and b/src/assets/tabbar/my-sel.png differ diff --git a/src/assets/tabbar/my.png b/src/assets/tabbar/my.png new file mode 100755 index 0000000..cf911ee Binary files /dev/null and b/src/assets/tabbar/my.png differ diff --git a/src/assets/tabbar/order-sel.png b/src/assets/tabbar/order-sel.png new file mode 100755 index 0000000..132a4d8 Binary files /dev/null and b/src/assets/tabbar/order-sel.png differ diff --git a/src/assets/tabbar/order.png b/src/assets/tabbar/order.png new file mode 100755 index 0000000..eeea77e Binary files /dev/null and b/src/assets/tabbar/order.png differ diff --git a/src/assets/tongzhi.png b/src/assets/tongzhi.png new file mode 100755 index 0000000..b5fb4ce Binary files /dev/null and b/src/assets/tongzhi.png differ diff --git a/src/assets/zheng.png b/src/assets/zheng.png new file mode 100755 index 0000000..e3092f5 Binary files /dev/null and b/src/assets/zheng.png differ diff --git a/src/components/.gitkeep b/src/components/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/src/components/agreed-comp/agreed-comp.vue b/src/components/agreed-comp/agreed-comp.vue new file mode 100644 index 0000000..66f6627 --- /dev/null +++ b/src/components/agreed-comp/agreed-comp.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/src/components/button-contact/button-contact.vue b/src/components/button-contact/button-contact.vue new file mode 100644 index 0000000..aa9a579 --- /dev/null +++ b/src/components/button-contact/button-contact.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/src/components/choose-avatar/choose-avatar.vue b/src/components/choose-avatar/choose-avatar.vue new file mode 100755 index 0000000..0cabe0d --- /dev/null +++ b/src/components/choose-avatar/choose-avatar.vue @@ -0,0 +1,82 @@ + + + + + diff --git a/src/components/dict-picker/dict-picker.vue b/src/components/dict-picker/dict-picker.vue new file mode 100755 index 0000000..bac1405 --- /dev/null +++ b/src/components/dict-picker/dict-picker.vue @@ -0,0 +1,112 @@ + + + diff --git a/src/components/popup-checkbox/popup-checkbox.vue b/src/components/popup-checkbox/popup-checkbox.vue new file mode 100644 index 0000000..0549856 --- /dev/null +++ b/src/components/popup-checkbox/popup-checkbox.vue @@ -0,0 +1,62 @@ + + + + + diff --git a/src/components/tabbar/tabbar.vue b/src/components/tabbar/tabbar.vue new file mode 100755 index 0000000..1482977 --- /dev/null +++ b/src/components/tabbar/tabbar.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/src/components/upload-img/upload-img.vue b/src/components/upload-img/upload-img.vue new file mode 100644 index 0000000..ac9d7f7 --- /dev/null +++ b/src/components/upload-img/upload-img.vue @@ -0,0 +1,74 @@ + + + + diff --git a/src/configs/devServer.js b/src/configs/devServer.js new file mode 100755 index 0000000..3bb9ddc --- /dev/null +++ b/src/configs/devServer.js @@ -0,0 +1,9 @@ +export { + useProxy, + requestURL as proxyURL, + proxyPath, + proxyPort, + appBasePath, + requestPath, + requestFilePath, +} from './index' diff --git a/src/configs/dict/index.js b/src/configs/dict/index.js new file mode 100755 index 0000000..651b08c --- /dev/null +++ b/src/configs/dict/index.js @@ -0,0 +1,14 @@ +export const approveStatus = [ + { + dictLabel: '待审核', + dictValue: 1, + }, + { + dictLabel: '审核通过', + dictValue: 2, + }, + { + dictLabel: '审核拒绝', + dictValue: 3, + }, +] diff --git a/src/configs/index.js b/src/configs/index.js new file mode 100755 index 0000000..7afd54b --- /dev/null +++ b/src/configs/index.js @@ -0,0 +1,28 @@ +import { isH5 } from '@uni-helper/uni-env' + +const isProduction = process.env.NODE_ENV === 'production' + +export const appName = 'Escort' + +// 项目主题色 +export const primaryColor = '#FF8CA6' + +// 项目基础路径 +export const appBasePath = isProduction ? './' : './' +// 请求地址 +export const requestURL = 'http://192.168.2.155:7788/hospital/app' +export const requestPath = '' +export const requestFilePath = '/file' +// 是否开启代理 +export const useProxy = isH5 +// 代理路径 +export const proxyPath = '/proxy' +// 代理端口号 +export const proxyPort = 1996 +// 是否开启加密 +export const useEncrypt = false +// 是否使用远程导航菜单 +export const useRemoteMenu = true + +// 主页面路径 +export const homePage = 'pages/index/home/index' diff --git a/src/configs/menu/index.js b/src/configs/menu/index.js new file mode 100755 index 0000000..5d08962 --- /dev/null +++ b/src/configs/menu/index.js @@ -0,0 +1,9 @@ +export default [ + { + parentId: '/', + id: '/', + path: '/', + meta: { title: '首页', icon: '' }, + children: [], + }, +] diff --git a/src/configs/request.js b/src/configs/request.js new file mode 100755 index 0000000..2c93bb1 --- /dev/null +++ b/src/configs/request.js @@ -0,0 +1,44 @@ +import { + proxyPath, + requestFilePath, + requestPath, + requestURL, + useProxy, +} from './index' + +const isDevelopment = process.env.NODE_ENV === 'development' + +// 请求基础域名 +export function getBaseURL () { + let tempURL = '' + if (useProxy) { + tempURL = isDevelopment ? proxyPath : window.location.origin + requestPath + } + else { + tempURL = requestURL + requestPath + } + return tempURL +} + +// 文件基础域名 +export function getFileBaseURL () { + let tempURL = '' + if (useProxy) { + tempURL = isDevelopment + ? requestFilePath + : window.location.origin + requestFilePath + } + else { + tempURL = requestURL + requestFilePath + } + return tempURL +} + +// 请求域名 +export const baseURL = getBaseURL() +// 响应成功code值 +export const responseSuccessCode = 200 +// 超时时间 +export const timeout = 20 * 1000 +// 是否开启加密 +export { useEncrypt } from './index' diff --git a/src/icons/components/ViaIcon/index.vue b/src/icons/components/ViaIcon/index.vue new file mode 100755 index 0000000..d5f823e --- /dev/null +++ b/src/icons/components/ViaIcon/index.vue @@ -0,0 +1,31 @@ + + + diff --git a/src/icons/fonts/iconfont.css b/src/icons/fonts/iconfont.css new file mode 100755 index 0000000..1ab7872 --- /dev/null +++ b/src/icons/fonts/iconfont.css @@ -0,0 +1,50 @@ +@font-face { + font-family: "iconfont"; /* Project id 3854221 */ + src: + url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAeUAAsAAAAADdgAAAdHAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGYACEAAqNJIp+ATYCJAMoCxYABCAFhGcHgR4b2AtRVHCqyH4kVLdVMI95iXryNL07cjVxNxNmRFDfDaUkiNbK6pmFoxCSiyRQBOrzQoVQAWkgoeNQkYpF9Rjhb7Lu/dRbanvJc2GdjGTB5mX7CRxOPok8/elgzpaAt3gF9+0FvoL/8Ap2Khv28xQ8ueO1+Zm2ZyKI6/+/n8sTi1v6dXKHWS/3ze/M34aJtEUah9IWEiYWOYTK4XQaoXRsXt1iPCtJM2OW8lxS41YhlV/DTQRaVivmurO6sQUE9AxSFbDc2XODpH/0CNwgYKSQokEdGt6KumMhHihJ99Jl3GffH8PWBkNSZvZh9p2vGgFn3ho/J7vN7CLyL4F5vEm4ckKJjOUri8TN5uRlbhEtZ65W1V8VDgA6GpKib/Xbhe+uvDv4OXm8S1/K23kZu90zdIw03gkAPUYoVWqNcf/xmkSFc3VAdtHZPEmLl0uiLzWXgr55uZT0zWdGqb4FkEtN38JcGvRfySUz0JFL8D85pAmS1tDxgElAmgWeLyDbNbaWFZJwPjSPDmLcp3m77y8PCQ3y958fHRIcElbrF3gieCxsh8NUBz2B2MBwZD2KMunxRIfDVY0ahzOAGbQgPSYNTTSgRNDCGhyangvVGgqXTXHmLxyC+uk2oGEwtqsOYkPWoJabm3EaL9vTWNGaprknKw53hrtVTyTydPXo6ZxkSweeTlJBlMpTM11EciF3ISeKnNyZkYKUgl8jRSblUyVCoKJ3rpJUBy/HFS5XHCovawWzFYcdikUdy2QVs2JG22oZW4EUm7dERAhImfkzRGSjFYeC5yfPrEwOZKIBB5kxHzxwR70rSnK7ELq1N9B6Gt8qjG7vkpTeu+qdxFF8p9ZJxM1uHcZlWSi7nFTmJudUnNoaT7E6F0tiELCl7oQkCDg82yQFWEMn9iiW79wxQVXu3hWIdPu2gMRbt44YEuKI10rYQCvigmw00eP4M8F2nF0ik0wOCbIRXT3zYiXOjHoGcYd6CkOLMmK5oEBrDNeB5TlUzwyNqqVaWLy1ZUYdgOq7SW8jDLWhh5oyRLelIO6q3vT2qqpb290VFK5C1TSpnF4bLL1L6xIJrlbhmqiyllSba/kCHihDwOlBqr4xssMzscXbR9xbrLMVzBdWY/NggS9MBVv7kbwxlGln4xNswCuv5+dgMtnJOy/xM6/N4NcGui9mTl4kLyozvMEvtlA/mC7mEfNYj8VGDIYdnVATJXid1V5YuBfvgm4KnMVQUeZlavs452NbHLK00sCZjdHyvR8WfqDyjOAVVTOn5ixVWTGg/HFPZeA1pV4CtXZxa+B8N1RcizKhU47ePeP/33wqmIBwbPn9Eb0cGG1Cr29sgZcJBPAS8mP9ODMYrZcbcX+5QJGaFoIA8uZ90fVeApQP8jIVxPpyFgha+Hzlpzn9JiyatMH758prFJ86O3FlMLvw5t3rIE76T2SYuzvW7C5cQ0bXFO62BCGFmQts9GLu+LmgamrGwEDmtEUZ0wJ//vzxM3Dd1MUdH/wsUGlKrI1PqG1PqAtqj6rq2uNrYZBrzMOt2VsfZpWNPI5+BfW75zuwzfqkohzn4J07cXn5E6uVaygObnX5Ut6Ed+6sPVBTxRerDR84x/c5uu3Lltm7HX3XDQM3nvP3Oa5XbARmXOnOvBTSmX5pRsun2E++0cOA8VNCH4LND56K4iXzJepywrzIfLnRpsvvKpD7qI4zpTGGLTSfEMXL5svNS4JHO2a0XEoTQx92Zw7W+ejX4ICHV1rmAcJAfhwPPbs/q7czuztHgpJj4oHXoi76mThLqYXdVb2LZZtFr7Z4dPVsrI1vSGyH7Q0ngowct6yO/j9bQnr5lOShkq0TlrGmr+VfTeEZu9oCVp1LbOxJKYsrtcQ97illWzNb2WD06U42cyZ0ialKb8KCGR8Auv/yu8wwbXJ+kg90issb88i4/M7VwiVfg/Q/B+RnqQ2CabiqTzchv8i7v/kr+XNt+1+fwMI/TPvXoP7fv6M7uMnjtTYkyObvedXRAnTt2YowamkVH4vJHqNMX7SMM0rLGzXfmoCWU0EXK8Z6OrZnHNnyh+IZl0BSmwZZw1xRIVsKpba1UGnYAS3LVFGbW13nJoomFpoDEEY7BMlI7yEb7ZyokN2D0kTvoDLaf2g5Ev6ONg4QwxUEDVI0AocmQWFYU7F5KUu3CXGGPEjKGtsQcQqoh2nJqfn2GqQiMsQmzjEunVIMMdEUWC2cDsmyBnWiiWiYJvOU6vkpKbhqk+RhTQEVCGQQDbKOgIZMKikYplHh1DT785ogHINsECGK2jjh5EyYPpQmWSpBVONSSdOuZKjTGE46ihyDHhFsU0DVEoJksUUD6dVNImRYTybjezTp8qU4qTDVlTy/R3nUtt+QGeytW5EiRxFlVFFHI5q/EAdTX0iSjUmawRCkTuaRynmNCN40AQleo+xEw7wROEiINiFJRpgmDWnyiH82ZOiitcExMlwqSINqicDxbbu7SwgbAAA=') format('woff2'), + url('//at.alicdn.com/t/c/font_3854221_ct02qwtu5gl.ttf?t=1691462687498') format('truetype'); +} + +.iconfont { + font-family: "iconfont" !important; + /* font-size: 16px; */ + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-m-luyou:before { + content: "\e858"; +} + +.icon-renzheng:before { + content: "\e62f"; +} + +.icon-dingwei:before { + content: "\e7cd"; +} + +.icon-qingchu:before { + content: "\e630"; +} + +.icon-arrow-left-bold:before { + content: "\e685"; +} + +.icon-arrow-up-bold:before { + content: "\e686"; +} + +.icon-arrow-down-bold:before { + content: "\e687"; +} + +.icon-arrow-right-bold:before { + content: "\e688"; +} + +.icon-kefu:before { + content: "\ec2e"; +} diff --git a/src/icons/index.js b/src/icons/index.js new file mode 100755 index 0000000..6ceb78b --- /dev/null +++ b/src/icons/index.js @@ -0,0 +1,7 @@ +import ViaIcon from './components/ViaIcon/index.vue' + +export default { + install(app) { + app.component('ViaIcon', ViaIcon) + }, +} diff --git a/src/main.js b/src/main.js new file mode 100755 index 0000000..febd354 --- /dev/null +++ b/src/main.js @@ -0,0 +1,51 @@ +import { createSSRApp } from 'vue' + +import 'virtual:uno.css' + +import App from './App.vue' + +import store from './store/index.js' + +import router from './router/index.js' +// import routerGuards from './router/guards/index.js' + +import api from './api/index.js' +import plugins from './plugins/index.js' +import mixins from './mixins/index.js' + +import ViaIcon from './icons/components/ViaIcon/index.vue' +import { useDialog, useLoading, useToast } from './utils/modals/index.js' +import _showDictLabel from './utils/showDictLabel.js' + +// 为 remote 时使用远程静态资源 常用于小程序 +// 为 local 时使用本地静态资源 +// import { useAssets } from './utils/assets/remote.js' +import { useAssets } from './utils/assets/local.js' + +export function createApp () { + const app = createSSRApp(App) + + app.use(store) + + app.use(router) + // app.use(routerGuards, router) + + app.use(api) + app.use(plugins) + app.use(mixins) + app.component('ViaIcon', ViaIcon) + + app.config.globalProperties.$dialog = useDialog + app.config.globalProperties.$toast = useToast + app.config.globalProperties.$loading = useLoading + + app.config.globalProperties.$showDictLabel = _showDictLabel + + // 静态资源加载工具 + app.config.globalProperties.$assets = useAssets + + return { + app, + Pinia: store.Pinia, + } +} diff --git a/src/manifest.json b/src/manifest.json new file mode 100755 index 0000000..a7f46e6 --- /dev/null +++ b/src/manifest.json @@ -0,0 +1,72 @@ +{ + "name": "vite-uniapp-template", + "appid": "", + "description": "", + "versionName": "2.0.0", + "versionCode": "100", + "transformPx": false, + "app-plus": { + "usingComponents": true, + "nvueStyleCompiler": "uni-app", + "compilerVersion": 3, + "splashscreen": { + "alwaysShowBeforeRender": true, + "waiting": true, + "autoclose": true, + "delay": 0 + }, + "modules": {}, + "distribute": { + "android": { + "permissions": [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + "ios": {}, + "sdkConfigs": {} + } + }, + "quickapp": {}, + "mp-weixin": { + "appid": "wx55ff808ba0e28b1d", + "setting": { + "urlCheck": false, + "ignoreUploadUnusedFiles": false, + "ignoreDevUnusedFiles": false + }, + "usingComponents": true, + "permission": { + "scope.userLocation": { + "desc": "你的位置信息将用于小程序位置接口的效果展示" + } + }, + "requiredPrivateInfos": ["getLocation", "chooseLocation"] + }, + "mp-alipay": { + "usingComponents": true + }, + "mp-baidu": { + "usingComponents": true + }, + "mp-toutiao": { + "usingComponents": true + }, + "uniStatistics": { + "enable": false + }, + "vueVersion": "3" +} diff --git a/src/mixins/index.js b/src/mixins/index.js new file mode 100755 index 0000000..944e09f --- /dev/null +++ b/src/mixins/index.js @@ -0,0 +1,7 @@ +import share from './share/index.js' + +export default { + install(app) { + app.mixin(share) + }, +} diff --git a/src/mixins/share/index.js b/src/mixins/share/index.js new file mode 100755 index 0000000..01a7481 --- /dev/null +++ b/src/mixins/share/index.js @@ -0,0 +1,24 @@ +import { appName } from '@/configs/index' + +export default { + data() { + return { + shareAppMessageProps: {}, + shareTimelineProps: {}, + } + }, + onShareAppMessage() { + return { + title: appName, + path: '/pages/index/index', + ...this.shareAppMessageProps, + } + }, + onShareTimeline() { + return { + title: appName, + query: '', + ...this.shareTimelineProps, + } + }, +} diff --git a/src/pages.json b/src/pages.json new file mode 100755 index 0000000..1c9e388 --- /dev/null +++ b/src/pages.json @@ -0,0 +1,175 @@ +{ + "easycom": { + "autoscan": true, + "custom": { + "^u-(.*)": "uview-plus/components/u-$1/u-$1.vue", + "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue", + "^(?!z-paging-refresh|z-paging-load-more)z-paging(.*)": "z-paging/components/z-paging$1/z-paging$1.vue" + } + }, + "pages": [ + { + "path": "pages/index/home/index", + "aliasPath": "/", + "meta": { + "key": "home" + }, + "style": { + "navigationBarTitleText": "" + }, + "type": "home" + }, + { + "path": "pages/index/order/index", + "aliasPath": "/order", + "meta": { + "key": "order" + }, + "style": { + "navigationBarTitleText": "订单" + } + }, + { + "path": "pages/index/personal/index", + "aliasPath": "/personal", + "meta": { + "key": "personal" + }, + "style": { + "navigationBarTitleText": "我的" + } + }, + { + "path": "pages/login/index", + "aliasPath": "/login", + "style": { + "navigationBarTitleText": "登录" + } + }, + { + "path": "pages/errors/404/index", + "aliasPath": "/404", + "style": { + "navigationBarTitleText": "404" + } + } + ], + "subPackages": [ + { + "root": "pages/webview", + "pages": [ + { + "path": "index", + "aliasPath": "/webview", + "style": { + "navigationBarTitleText": "webview" + } + } + ] + }, + { + "root": "pages/form", + "pages": [ + { + "path": "index", + "aliasPath": "/form", + "style": { + "navigationBarTitleText": "填写订单" + } + }, + { + "path": "complete", + "aliasPath": "/complete", + "style": { + "navigationBarTitleText": "订单完成" + } + } + ] + }, + { + "root": "pages/other", + "pages": [ + { + "path": "income-details", + "aliasPath": "/income-details", + "style": { + "navigationBarTitleText": "收入详情" + } + }, + { + "path": "edit-userinfo", + "aliasPath": "/edit-userinfo", + "style": { + "navigationBarTitleText": "编辑资料" + } + }, + { + "path": "switch", + "aliasPath": "/switch", + "style": { + "navigationBarTitleText": "成为陪诊师" + } + } + ] + }, + { + "root": "pages/statement", + "pages": [ + { + "path": "index", + "aliasPath": "/statement", + "style": { + "navigationBarTitleText": "产品服务协议" + } + } + ] + }, + { + "root": "pages/realname", + "pages": [ + { + "path": "index", + "aliasPath": "/realname", + "style": { + "navigationBarTitleText": "实名认证" + } + } + ] + }, + { + "root": "pages/contact", + "pages": [ + { + "path": "index", + "aliasPath": "/contact", + "style": { + "navigationBarTitleText": "联系我们" + } + } + ] + } + ], + "tabBar": { + "list": [ + { + "pagePath": "pages/index/home/index" + }, + { + "pagePath": "pages/index/order/index" + }, + { + "pagePath": "pages/index/personal/index" + } + ] + }, + "globalStyle": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "", + "navigationBarBackgroundColor": "#FF8CA6", + "backgroundColor": "#ffffff", + "usingComponents": { + "van-rate": "/wxcomponents/vant-weapp/rate", + "van-icon": "/wxcomponents/vant-weapp/icon" + } + } +} \ No newline at end of file diff --git a/src/pages/contact/index.vue b/src/pages/contact/index.vue new file mode 100755 index 0000000..e539560 --- /dev/null +++ b/src/pages/contact/index.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/src/pages/errors/404/index.vue b/src/pages/errors/404/index.vue new file mode 100755 index 0000000..7377f48 --- /dev/null +++ b/src/pages/errors/404/index.vue @@ -0,0 +1,12 @@ + + + + + diff --git a/src/pages/form/complete.vue b/src/pages/form/complete.vue new file mode 100644 index 0000000..3299f1f --- /dev/null +++ b/src/pages/form/complete.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/src/pages/form/index.vue b/src/pages/form/index.vue new file mode 100644 index 0000000..e54b47d --- /dev/null +++ b/src/pages/form/index.vue @@ -0,0 +1,536 @@ + + + + + diff --git a/src/pages/index/example/index.vue b/src/pages/index/example/index.vue new file mode 100755 index 0000000..7e20599 --- /dev/null +++ b/src/pages/index/example/index.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/src/pages/index/home/index.vue b/src/pages/index/home/index.vue new file mode 100755 index 0000000..f2de930 --- /dev/null +++ b/src/pages/index/home/index.vue @@ -0,0 +1,186 @@ + + + + + diff --git a/src/pages/index/order/index.vue b/src/pages/index/order/index.vue new file mode 100755 index 0000000..b5abbda --- /dev/null +++ b/src/pages/index/order/index.vue @@ -0,0 +1,215 @@ + + + + + diff --git a/src/pages/index/personal/index.vue b/src/pages/index/personal/index.vue new file mode 100755 index 0000000..5b4db6c --- /dev/null +++ b/src/pages/index/personal/index.vue @@ -0,0 +1,210 @@ + + + + + diff --git a/src/pages/login/index.vue b/src/pages/login/index.vue new file mode 100755 index 0000000..a9518f2 --- /dev/null +++ b/src/pages/login/index.vue @@ -0,0 +1,55 @@ + + + + + diff --git a/src/pages/login/phone/index.vue b/src/pages/login/phone/index.vue new file mode 100755 index 0000000..a9e1128 --- /dev/null +++ b/src/pages/login/phone/index.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/src/pages/middleware/index.vue b/src/pages/middleware/index.vue new file mode 100755 index 0000000..897194d --- /dev/null +++ b/src/pages/middleware/index.vue @@ -0,0 +1,11 @@ + + + + + diff --git a/src/pages/other/edit-userinfo.vue b/src/pages/other/edit-userinfo.vue new file mode 100644 index 0000000..c9ee225 --- /dev/null +++ b/src/pages/other/edit-userinfo.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/src/pages/other/income-details.vue b/src/pages/other/income-details.vue new file mode 100644 index 0000000..c159052 --- /dev/null +++ b/src/pages/other/income-details.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/src/pages/other/switch.vue b/src/pages/other/switch.vue new file mode 100644 index 0000000..37385b5 --- /dev/null +++ b/src/pages/other/switch.vue @@ -0,0 +1,267 @@ + + + + + diff --git a/src/pages/realname/components/Base/AreaPicker/trigger.vue b/src/pages/realname/components/Base/AreaPicker/trigger.vue new file mode 100755 index 0000000..c87fa28 --- /dev/null +++ b/src/pages/realname/components/Base/AreaPicker/trigger.vue @@ -0,0 +1,132 @@ + + + + + diff --git a/src/pages/realname/components/Base/index.vue b/src/pages/realname/components/Base/index.vue new file mode 100755 index 0000000..7df2faf --- /dev/null +++ b/src/pages/realname/components/Base/index.vue @@ -0,0 +1,219 @@ + + + + + diff --git a/src/pages/realname/components/Certificate/index.vue b/src/pages/realname/components/Certificate/index.vue new file mode 100755 index 0000000..8251024 --- /dev/null +++ b/src/pages/realname/components/Certificate/index.vue @@ -0,0 +1,179 @@ + + + + + diff --git a/src/pages/realname/components/Identity/index.vue b/src/pages/realname/components/Identity/index.vue new file mode 100755 index 0000000..cadd3e4 --- /dev/null +++ b/src/pages/realname/components/Identity/index.vue @@ -0,0 +1,154 @@ + + + + + diff --git a/src/pages/realname/components/Success/index.vue b/src/pages/realname/components/Success/index.vue new file mode 100755 index 0000000..d90cac7 --- /dev/null +++ b/src/pages/realname/components/Success/index.vue @@ -0,0 +1,50 @@ + + + + + diff --git a/src/pages/realname/index.vue b/src/pages/realname/index.vue new file mode 100755 index 0000000..28c4594 --- /dev/null +++ b/src/pages/realname/index.vue @@ -0,0 +1,135 @@ + + + + + diff --git a/src/pages/statement/index.vue b/src/pages/statement/index.vue new file mode 100755 index 0000000..a7cadbd --- /dev/null +++ b/src/pages/statement/index.vue @@ -0,0 +1,20 @@ + + + + + diff --git a/src/pages/webview/index.vue b/src/pages/webview/index.vue new file mode 100755 index 0000000..ee89796 --- /dev/null +++ b/src/pages/webview/index.vue @@ -0,0 +1,25 @@ + + + + + diff --git a/src/plugins/index.js b/src/plugins/index.js new file mode 100755 index 0000000..b146122 --- /dev/null +++ b/src/plugins/index.js @@ -0,0 +1,7 @@ +import UviewPlus from './uview-plus' + +export default { + install(app) { + app.use(UviewPlus) + }, +} diff --git a/src/plugins/uview-plus/index.js b/src/plugins/uview-plus/index.js new file mode 100755 index 0000000..59896b2 --- /dev/null +++ b/src/plugins/uview-plus/index.js @@ -0,0 +1,7 @@ +import uviewPlus from 'uview-plus' + +export default { + install(app) { + app.use(uviewPlus) + }, +} diff --git a/src/plugins/uview-plus/styles/theme.scss b/src/plugins/uview-plus/styles/theme.scss new file mode 100755 index 0000000..7110b66 --- /dev/null +++ b/src/plugins/uview-plus/styles/theme.scss @@ -0,0 +1,48 @@ +// 此文件为uView的主题变量,这些变量目前只能通过uni.scss引入才有效,另外由于 +// uni.scss中引入的样式会同时混入到全局样式文件和单独每一个页面的样式中,造成微信程序包太大, +// 故uni.scss只建议放scss变量名相关样式,其他的样式可以通过main.js或者App.vue引入 + +$u-main-color: #303133; +$u-content-color: #606266; +$u-tips-color: #909193; +$u-light-color: #c0c4cc; +$u-border-color: #dadbde; +$u-bg-color: #f3f4f6; +$u-disabled-color: #c8c9cc; + +/* $u-primary: #3c9cff; +$u-primary-dark: #398ade; +$u-primary-disabled: #9acafc; +$u-primary-light: #ecf5ff; */ +$u-primary: rgba(var(--color-primary), 1); +$u-primary-dark: rgba(var(--color-primary-700), 1); +$u-primary-disabled: rgba(var(--color-primary-300), 1); +$u-primary-light: rgba(var(--color-primary-100), 1); + +$u-warning: #f9ae3d; +$u-warning-dark: #f1a532; +$u-warning-disabled: #f9d39b; +$u-warning-light: #fdf6ec; + +$u-success: #5ac725; +$u-success-dark: #53c21d; +$u-success-disabled: #a9e08f; +$u-success-light: #f5fff0; + +$u-error: #f56c6c; +$u-error-dark: #e45656; +$u-error-disabled: #f7b2b2; +$u-error-light: #fef0f0; + +$u-info: #909399; +$u-info-dark: #767a82; +$u-info-disabled: #c4c6c9; +$u-info-light: #f4f4f5; + +// scss混入,为了少写几行#ifndef +@mixin flex($direction: row) { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: $direction; +} diff --git a/src/router/guards/index.js b/src/router/guards/index.js new file mode 100755 index 0000000..68f4c2f --- /dev/null +++ b/src/router/guards/index.js @@ -0,0 +1,9 @@ +import permission from './permission/index.js' +import realname from './realname/index.js' + +import { defineMiddleware } from '$uni-router/middleware' + +export default (app, router) => { + permission(router, { app }) + defineMiddleware('realname', realname, { router, app }) +} diff --git a/src/router/guards/permission/index.js b/src/router/guards/permission/index.js new file mode 100755 index 0000000..49eda82 --- /dev/null +++ b/src/router/guards/permission/index.js @@ -0,0 +1,65 @@ +// import { useToast } from '@/utils/modals' +import store from '@/store/index.js' + +const homePath = '/pages/index/home/index' +const loginPath = '/pages/login/phone/index' + +const whiteList = [loginPath, '/pages/statement/index', '/pages/webview/index'] + +const permission = (router) => { + const userStore = store.useUserStore() + + const loginRoute = to => ({ + path: loginPath, + navType: 'reLaunch', + force: true, + query: { + redirect: JSON.stringify({ + path: to.path, + query: to.query, + }), + }, + }) + + router.beforeEach((to, from, next) => { + // console.log('permission.beforeEach.to', to) + // console.log('permission.beforeEach.from', from) + + const token = userStore.token + const userId = userStore.userId + + // console.log('token', token) + // console.log('userId', userId) + + if (token) { + if (to.path === loginPath) { + next(homePath) + } + else if (userId) { + next() + } + else { + userStore + .getUserInfo() + .then(() => { + next() + }) + .catch((error) => { + console.warn(error) + userStore.logout({ silenced: true }) + next(loginRoute(to)) + }) + } + } + else if (whiteList.includes(to.path)) { + next() + } + else { + next(loginRoute(to)) + } + }) + + // router.afterEach(() => {}) +} + +export default permission diff --git a/src/router/guards/realname/index.js b/src/router/guards/realname/index.js new file mode 100755 index 0000000..9f5b904 --- /dev/null +++ b/src/router/guards/realname/index.js @@ -0,0 +1,49 @@ +import store from '@/store/index.js' +import { useDialog, useToast } from '@/utils/modals' + +const realname = (router) => { + const userStore = store.useUserStore() + + router.beforeEach((to, from, next) => { + // console.log('realname.beforeEach.to', to) + // console.log('realname.beforeEach.from', from) + + const realStatus = userStore.userInfo.realStatus + + switch (realStatus) { + case 3: + next() + break + case 2: + useToast('实名审核中, 请稍后再试').then(() => { + next(false) + }) + break + case 4: + useDialog(`${userStore.userInfo.auditResult || '提交的实名信息不符'}`, { + title: '实名失败', + showCancelButton: true, + confirmText: '重新认证', + }) + .then(() => { + next({ path: '/pages/realname/index' }) + }) + .catch(() => { + next(false) + }) + break + default: + useDialog('请先进行实名认证', { showCancelButton: true }) + .then(() => { + next({ path: '/pages/realname/index' }) + }) + .catch(() => { + next(false) + }) + break + } + }) + // router.afterEach(() => {}) +} + +export default realname diff --git a/src/router/index.js b/src/router/index.js new file mode 100755 index 0000000..d3b91f2 --- /dev/null +++ b/src/router/index.js @@ -0,0 +1,20 @@ +import { createRouter } from '$uni-router' +import pages from '@/pages.json' + +// console.log('pages', pages) + +const router = createRouter({ + pages, + addRoutes: [ + { + path: '*', + redirect: () => { + return { path: '/404' } + }, + }, + ], +}) + +// console.log('router', router) + +export default router diff --git a/src/static/avatar.png b/src/static/avatar.png new file mode 100755 index 0000000..090ca2e Binary files /dev/null and b/src/static/avatar.png differ diff --git a/src/static/logo.png b/src/static/logo.png new file mode 100755 index 0000000..b5771e2 Binary files /dev/null and b/src/static/logo.png differ diff --git a/src/static/tabbar/tab-example-active.png b/src/static/tabbar/tab-example-active.png new file mode 100755 index 0000000..7501011 Binary files /dev/null and b/src/static/tabbar/tab-example-active.png differ diff --git a/src/static/tabbar/tab-example.png b/src/static/tabbar/tab-example.png new file mode 100755 index 0000000..fd1e942 Binary files /dev/null and b/src/static/tabbar/tab-example.png differ diff --git a/src/static/tabbar/tab-home-active.png b/src/static/tabbar/tab-home-active.png new file mode 100755 index 0000000..26d3761 Binary files /dev/null and b/src/static/tabbar/tab-home-active.png differ diff --git a/src/static/tabbar/tab-home.png b/src/static/tabbar/tab-home.png new file mode 100755 index 0000000..8f82e21 Binary files /dev/null and b/src/static/tabbar/tab-home.png differ diff --git a/src/static/tabbar/tab-personal-active.png b/src/static/tabbar/tab-personal-active.png new file mode 100755 index 0000000..8c3e66e Binary files /dev/null and b/src/static/tabbar/tab-personal-active.png differ diff --git a/src/static/tabbar/tab-personal.png b/src/static/tabbar/tab-personal.png new file mode 100755 index 0000000..0a569a2 Binary files /dev/null and b/src/static/tabbar/tab-personal.png differ diff --git a/src/store/app/index.js b/src/store/app/index.js new file mode 100755 index 0000000..07f6f79 --- /dev/null +++ b/src/store/app/index.js @@ -0,0 +1,41 @@ +import { defineStore } from 'pinia' +import storage from '@/utils/storages' +import { getSiteConfig } from '@/api/base/index' +import { primaryColor } from '@/configs/index.js' + +export const useAppStore = defineStore({ + id: 'app', + state () { + return { + themeConfig: storage.get('app/themeConfig') || { + primaryColor, + }, + siteInfo: {}, + systemInfo: {}, + } + }, + getters: { + primaryColor: state => state.themeConfig?.primaryColor, + }, + actions: { + getSystemInfo () { + return new Promise((resolve) => { + uni.getSystemInfoSync({ + success: (res) => { + this.systemInfo = res + resolve(res) + }, + }) + }) + }, + async getSiteConfig () { + const res = await getSiteConfig() + if (res.success) { + const { title } = res.data + this.siteInfo = { + appName: title, + } + } + }, + }, +}) diff --git a/src/store/dict/index.js b/src/store/dict/index.js new file mode 100755 index 0000000..2c9b406 --- /dev/null +++ b/src/store/dict/index.js @@ -0,0 +1,35 @@ +import { defineStore } from 'pinia' +import { getDictList } from '@/api/base/index' +import * as staticDict from '@/configs/dict/index' + +export const useDictStore = defineStore({ + id: 'app-dict', + state() { + return { + dictModel: {}, + dictData: { + ...staticDict, + }, + } + }, + actions: { + async getDictData(key) { + let tempData = [] + if (this.dictData[key]) { + tempData = this.dictData[key] + } + else { + const { code, data } = await getDictList(this.dictModel[key] || key) + if (success) { + tempData = data.map(item => ({ + ...item, + label: item.dictLabel, + value: item.dictValue, + })) + this.dictData[key] = tempData + } + } + return tempData + }, + }, +}) diff --git a/src/store/index.js b/src/store/index.js new file mode 100755 index 0000000..0f95a85 --- /dev/null +++ b/src/store/index.js @@ -0,0 +1,25 @@ +import * as Pinia from 'pinia' +import { useAppStore } from './app/index.js' +import { useMenuStore } from './menu/index.js' +import { useUserStore } from './user/index.js' +import { useDictStore } from './dict/index.js' + +export default { + install(app) { + app.use(Pinia.createPinia()) + app.config.globalProperties.$store = { + app: useAppStore(), + menu: useMenuStore(), + user: useUserStore(), + dict: useDictStore(), + } + + app.config.globalProperties.$permission = key => + useMenuStore().permission[key] + }, + useAppStore, + useMenuStore, + useUserStore, + useDictStore, + Pinia, +} diff --git a/src/store/menu/helpers.js b/src/store/menu/helpers.js new file mode 100755 index 0000000..9455fae --- /dev/null +++ b/src/store/menu/helpers.js @@ -0,0 +1,93 @@ +import { groupBy } from 'lodash-es' +import { list2Tree, tree2List } from '@/utils/treeSimple' +import { sortTreeByField } from '@/utils/tree' +import { getUserMenus } from '@/api/user/index' + +export async function getRemoteMenu(params) { + let data = [] + try { + const res = await getUserMenus(params) + + data = res?.data || [] + } + catch (error) { + console.log('error', error) + } + // console.log('getRemoteMenu.data', data) + return data +} + +export function transformerMenu(data, + { + pathKey = 'menuHref', + titleKey = 'menuName', + iconKey = 'menuIcon', + menuType = 'menuType', + menuSort = 'menuSort', + idKey = 'id', + parentKey = 'parentId', + childrenKey = 'children', + permissionKey = 'permission', + isTree = false, + } = {}) { + if (isTree) { + data = tree2List(data, { + key: idKey, + parentKey, + children: childrenKey, + }) + } + + data = data.filter(item => item.showFlag === '1') + + const { + 0: categoryList = [], + 1: menuList = [], + 2: permissionList = [], + } = groupBy(data, menuType) + + const rawRoutes = [] + const mapRoutes = rawRoutes.reduce((obj, item) => { + obj[item.path] = item + return obj + }, {}) + + let menu = []; + [...categoryList, ...menuList].forEach((item) => { + const routeItem = mapRoutes[item[pathKey]] + + const meta = { + ...(item[titleKey] ? { title: item[titleKey] } : {}), + ...(item[iconKey] ? { icon: `${item[iconKey]} fa-fw` } : {}), + } + menu.push({ + id: item[idKey], + parentId: item[parentKey], + path: item[pathKey], + sort: item[menuSort], + meta, + }) + + if (routeItem) { + routeItem.meta.title = meta.title || routeItem.meta.title + routeItem.meta.icon = meta.icon || routeItem.meta.icon + } + }) + + menu = list2Tree(menu, { + key: 'id', + parentKey: 'parentId', + children: 'children', + }) + + menu = sortTreeByField(menu, menuSort) + + const permission = permissionList.reduce((obj, item) => { + if (item[permissionKey]) { + obj[item[permissionKey]] = true + } + return obj + }, {}) + + return { menu, permission } +} diff --git a/src/store/menu/index.js b/src/store/menu/index.js new file mode 100755 index 0000000..3a33a4d --- /dev/null +++ b/src/store/menu/index.js @@ -0,0 +1,54 @@ +import { defineStore } from 'pinia' +import { getRemoteMenu, transformerMenu } from './helpers' +import { tree2List } from '@/utils/treeSimple' +import localMenu from '@/configs/menu/index.js' +import { useRemoteMenu } from '@/configs/index' + +export const useMenuStore = defineStore({ + id: 'app-menu', + state () { + return { + useRemoteMenu, + subKey: '', + treeMenu: [], + permission: {}, + } + }, + getters: { + flatMenu: state => tree2List(state.treeMenu), + mapMenu (state) { + const value = state.flatMenu.reduce((obj, item) => { + obj[item.path] = item + return obj + }, {}) + return value + }, + subMenus: (state) => { + let value = [] + if (state.subKey) { + const findMenu = state.treeMenu.find( + item => item.path === state.subKey, + ) + value = findMenu?.children || [] + } + return value + }, + }, + actions: { + async getUserMenu () { + if (!this.useRemoteMenu) { + this.treeMenu = localMenu + return this.treeMenu + } + + const params = {} + const data = await getRemoteMenu(params) + const { menu, permission } = transformerMenu(data) + console.log("🚀 ~ file: index.js:47 ~ permission:", permission) + console.log("🚀 ~ file: index.js:47 ~ menu:", menu) + this.treeMenu = menu + this.permission = permission + return this.treeMenu + }, + }, +}) diff --git a/src/store/user/index.js b/src/store/user/index.js new file mode 100755 index 0000000..29fb0b4 --- /dev/null +++ b/src/store/user/index.js @@ -0,0 +1,125 @@ +import { defineStore } from 'pinia' +import { getToken, removeToken, setToken, getUserInfo as getStorageUserInfo, setUserInfo, removeUserInfo } from '@/utils/token.js' +import { getUserInfo, userLogin } from '@/api/user/index.js' +import defaultAvatar from '@/static/avatar.png' +import router from '@/router' +import { useToast } from '@/utils/modals/index.js' + +// import storage from '@/utils/storages' + +export const useUserStore = defineStore('app-user', { + state () { + return { + userInfo: getStorageUserInfo(), + token: getToken(), + } + }, + getters: { + userId: state => state.userInfo?.userId, + avatar: state => state.userInfo?.avatar, + username: state => state.userInfo?.username, + resumed: state => !!state.resumeInfo.id, + }, + actions: { + async login () { + return new Promise(async (resolve, reject) => { + const { code } = await uni.login({ + provider: 'weixin', + }) + const res = await userLogin({ code }) + if (res.code !== 200) { + reject('自动登录失败') + } + if (res.user?.id) { + this.setUserInfo(res.user) + this.setToken(res.token) + resolve(res.user) + } else uni.getUserInfo({ + provider: 'weixin', + success: ({ userInfo }) => { + // 获取用户信息成功 + this.setUserInfo(userInfo) + this.setToken(res.token) + resolve(userInfo) + }, + fail: (err) => { + useToast('微信登录失败,请先同意授权!', { + type: 'error', + duration: 2 * 1000, + }) + this.removeToken() + // 如果用户拒绝授权,可以引导用户打开授权设置页面 + if (err.errMsg === 'getUserInfo:fail auth deny') { + this.openAuthSetting() + } + reject('登录失败') + } + }) + }) + }, + removeToken () { + this.token = '' + removeToken() + }, + setToken (token) { + this.token = token + setToken(token) + }, + removeUserInfo () { + this.userInfo = {} + removeUserInfo() + }, + setUserInfo (userInfo = {}) { + this.userInfo = userInfo + setUserInfo(userInfo) + }, + // 获取用户详情 + // async getUserInfo ({ params = {}, ...options } = {}) { + // const res = await getUserInfo(params, options) + + // if (!res?.success) { + // throw new Error('获取用户信息失败') + // } + + // if (!res?.data) { + // throw new Error('获取用户信息失败, 没有获取到数据') + // } + + // const data = res.data + // this.userInfo = { + // ...data, + // userId: data.id, + // avatar: data.avatar || defaultAvatar, + // username: data.username, + // } + + // return this.userInfo + // }, + openAuthSetting () { + uni.openSetting({ + success: function (res) { + if (res.authSetting['scope.userInfo']) { + // 用户开启了授权,重新调用 `uni.getUserInfo` 获取用户信息 + getUserInfo() + } + } + }) + }, + logout ({ silenced = false, redirect = null } = {}) { + this.removeToken() + this.removeUserInfo() + // this.userInfo = {} + // this.resumeInfo = {} + + // if (!silenced) { + // router.replaceAll({ + // force: true, + // path: '/login', + // query: { + // redirect, + // }, + // }) + // } + }, + }, +}) diff --git a/src/styles/css/applet.css b/src/styles/css/applet.css new file mode 100755 index 0000000..877702d --- /dev/null +++ b/src/styles/css/applet.css @@ -0,0 +1,64 @@ +page, +view, +text, +scroll-view, +swiper, +swiper-item, +cover-view, +cover-image, +icon, +rich-text, +progress, +button, +checkbox, +form, +input, +label, +radio, +slider, +switch, +textarea, +navigator, +audio, +camera, +image, +video, +uni-base, +::before, +::after { + box-sizing: border-box; + border-width: 0; + border-style: solid; + border-color: theme("colors.gray.200"); +} + +page { + height: 100%; + background-color: theme("colors.gray.50"); +} + +button { + background-color: transparent; + border-radius: 0rpx; + padding: 0rpx; + margin: 0rpx; + display: inline-block; + line-height: 1; + font-size: 1rem; +} + +button::after { + border: none; +} + +navigator { + display: inline-block; +} + +.pt-topbar { + padding-top: var(--status-bar-height); +} + +.mt-topbar { + margin-top: var(--status-bar-height); +} diff --git a/src/styles/css/index.css b/src/styles/css/index.css new file mode 100755 index 0000000..125fbb9 --- /dev/null +++ b/src/styles/css/index.css @@ -0,0 +1,2 @@ +@import './applet.css'; +@import './overrides.css'; diff --git a/src/styles/css/overrides.css b/src/styles/css/overrides.css new file mode 100755 index 0000000..ee44b62 --- /dev/null +++ b/src/styles/css/overrides.css @@ -0,0 +1,6 @@ +page { + @apply bg-[f2f2f2]; +} +uni-button:after { + border: none !important; +} diff --git a/src/uni.scss b/src/uni.scss new file mode 100755 index 0000000..51bbe0e --- /dev/null +++ b/src/uni.scss @@ -0,0 +1,78 @@ +/** + * 这里是uni-app内置的常用样式变量 + * + * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 + * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App + * + */ + +/** + * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 + * + * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 + */ + +/* 颜色变量 */ + +/* 行为相关颜色 */ +$uni-color-primary: rgba(var(--color-primary), 1); +$uni-color-success: #4cd964; +$uni-color-warning: #f0ad4e; +$uni-color-error: #dd524d; + +/* 文字基本颜色 */ +$uni-text-color: #333; // 基本色 +$uni-text-color-inverse: #fff; // 反色 +$uni-text-color-grey: #999; // 辅助灰色,如加载更多的提示信息 +$uni-text-color-placeholder: #808080; +$uni-text-color-disable: #c0c0c0; + +/* 背景颜色 */ +$uni-bg-color: #fff; +$uni-bg-color-grey: #f8f8f8; +$uni-bg-color-hover: #f1f1f1; // 点击状态颜色 +$uni-bg-color-mask: rgba(0, 0, 0, 0.4); // 遮罩颜色 + +/* 边框颜色 */ +$uni-border-color: #c8c7cc; + +/* 尺寸变量 */ + +/* 文字尺寸 */ +$uni-font-size-sm: 12px; +$uni-font-size-base: 14px; +$uni-font-size-lg: 16; + +/* 图片尺寸 */ +$uni-img-size-sm: 20px; +$uni-img-size-base: 26px; +$uni-img-size-lg: 40px; + +/* Border Radius */ +$uni-border-radius-sm: 2px; +$uni-border-radius-base: 3px; +$uni-border-radius-lg: 6px; +$uni-border-radius-circle: 50%; + +/* 水平间距 */ +$uni-spacing-row-sm: 5px; +$uni-spacing-row-base: 10px; +$uni-spacing-row-lg: 15px; + +/* 垂直间距 */ +$uni-spacing-col-sm: 4px; +$uni-spacing-col-base: 8px; +$uni-spacing-col-lg: 12px; + +/* 透明度 */ +$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 + +/* 文章场景相关 */ +$uni-color-title: #2c405a; // 文章标题颜色 +$uni-font-size-title: 20px; +$uni-color-subtitle: #555; // 二级标题颜色 +$uni-font-size-subtitle: 18px; +$uni-color-paragraph: #3f536e; // 文章段落颜色 +$uni-font-size-paragraph: 15px; + +@import '@/plugins/uview-plus/styles/theme.scss'; diff --git a/src/uni_modules/zb-dropdown-menu/changelog.md b/src/uni_modules/zb-dropdown-menu/changelog.md new file mode 100755 index 0000000..07b23fb --- /dev/null +++ b/src/uni_modules/zb-dropdown-menu/changelog.md @@ -0,0 +1,25 @@ +## 1.0.12(2023-04-18) +更新 +## 1.0.11(2023-04-10) +【fix】兼容vue3 修复报错 Right-hand side of 'instanceof' is not an object +【opti】优化下方列表滚动,感谢评论区大佬的意见 @touchmove.stop.prevent="moveHandle" +## 1.0.10(2023-01-30) +feature: 增加name 属性,默认触发事件 +## 1.0.9(2022-11-17) +fix:感谢评论区大佬给的建议 +## 1.0.8(2022-11-17) +优化项目 +## 1.0.7(2022-10-31) +1、优化 +## 1.0.6(2022-10-26) +优化细节 +## 1.0.5(2022-10-26) +fix: 小程序需手动在外层进行关闭 +## 1.0.4(2022-10-25) +fix:小程序运行报错原因 +## 1.0.3(2022-10-25) +优化弹出 +## 1.0.2(2022-10-22) +修改数据 +## 1.0.1(2022-10-22) +初始化 diff --git a/src/uni_modules/zb-dropdown-menu/components/zb-dropdown-item/zb-dropdown-item.vue b/src/uni_modules/zb-dropdown-menu/components/zb-dropdown-item/zb-dropdown-item.vue new file mode 100755 index 0000000..e372d16 --- /dev/null +++ b/src/uni_modules/zb-dropdown-menu/components/zb-dropdown-item/zb-dropdown-item.vue @@ -0,0 +1,465 @@ + + + + + diff --git a/src/uni_modules/zb-dropdown-menu/components/zb-dropdown-menu/zb-dropdown-menu.vue b/src/uni_modules/zb-dropdown-menu/components/zb-dropdown-menu/zb-dropdown-menu.vue new file mode 100755 index 0000000..f397529 --- /dev/null +++ b/src/uni_modules/zb-dropdown-menu/components/zb-dropdown-menu/zb-dropdown-menu.vue @@ -0,0 +1,410 @@ + + + + diff --git a/src/uni_modules/zb-dropdown-menu/package.json b/src/uni_modules/zb-dropdown-menu/package.json new file mode 100755 index 0000000..2660dfa --- /dev/null +++ b/src/uni_modules/zb-dropdown-menu/package.json @@ -0,0 +1,84 @@ +{ + "id": "zb-dropdown-menu", + "displayName": "zb-dropdown-menu 下拉筛选菜单 (多端兼容)", + "version": "1.0.12", + "description": "向下弹出的菜单列表。 ", + "keywords": [ + "下拉菜单", + "DropdownMenu", + "Dropdown", + "筛选", + "下拉" +], + "repository": "", +"engines": { + }, + "dcloudext": { + "type": "component-vue", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "Vue": { + "vue2": "y", + "vue3": "y" + }, + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y", + "钉钉": "y", + "快手": "y", + "飞书": "y", + "京东": "y" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/src/uni_modules/zb-dropdown-menu/readme.md b/src/uni_modules/zb-dropdown-menu/readme.md new file mode 100755 index 0000000..0621af7 --- /dev/null +++ b/src/uni_modules/zb-dropdown-menu/readme.md @@ -0,0 +1,70 @@ +# zb-dropdown-menu 向下弹出的菜单列表 + +### 微信=》 19550102670 拉进群 + +### 友情链接 +#### 在线预览点击 —— [企业级、通用型中后台前端解决方案 ](http://182.61.5.190:8889/) +#### vue-admin-perfect —— [企业级、通用型中后台前端解决方案(基于vue3.0+TS+Element-Plus 最新版,同时支持电脑,手机,平板)](https://github.com/zouzhibin/vue-admin-perfect) + + +### DropdownMenu Props 属性 +| 参数 | 说明 | 类型 | 可选值 | 默认值 |是否必须| +| ------ | ------ | ------ | ------ | ------ |------ | +| active-color | 菜单标题和选项的选中态颜色 | string |-- | #ee0a24 |必须 | +| z-index | 选项数组 | 菜单栏 z-index 层级,一个页面存在多个下拉选项的时候可以通过这个设置 |number/string | -- | | + + +### DropdownItem Props 属性 +| 参数 | 说明 | 类型 | 可选值 | 默认值 |是否必须| +| ------ | ------ | ------ | ------ | ------ |------ | +| value | 当前选中项对应的 value,可以通过v-model双向绑定 | number ,string |-- | -- |必须 | +| options | 选项数组 | Option[] |-- | -- |必须 | +| name | 必须指定,判断唯一值,不能重复 | String|Number |-- | -- |必须 | + + +##3 DropdownItem Events +| 参数 | 说明 | 回调参数 | +| ------ | ------ | ------ | ------ | ------ |------ | +| change | 点击选项导致 value 变化时触发 | item | + +### 注意 小程序没有window对象,需要自己在外层进行手动关闭 +``` + this.$refs.dropdown.close() +``` + +### 使用示例 +``` + + + + +``` + +### 数据格式 +``` +option: [ + { + text: '全部商品', + value: 0 + }, + { + text: '新款商品', + value: 1 + }, + { + text: '活动商品', + value: 2 + }, + ], +``` + diff --git a/src/utils/assets/local.js b/src/utils/assets/local.js new file mode 100755 index 0000000..e3573d3 --- /dev/null +++ b/src/utils/assets/local.js @@ -0,0 +1,14 @@ +const assets = import.meta.globEager('/src/assets/**/*') + +function useLocalAssets (filePath = '') { + let fileURL = '' + + fileURL = assets[`/src/assets${filePath}`].default + // console.log('fileURL', fileURL) + + return fileURL +} + +export const useAssets = useLocalAssets + +export default useLocalAssets diff --git a/src/utils/assets/remote.js b/src/utils/assets/remote.js new file mode 100755 index 0000000..26841f7 --- /dev/null +++ b/src/utils/assets/remote.js @@ -0,0 +1,17 @@ +import { getFileBaseURL } from '../../configs/request' + +function useRemoteAssets(filePath, { noCache = false } = {}) { + let fileURL = `${getFileBaseURL()}/assets${filePath}` + + if (noCache) { + fileURL += `?t=${new Date().getTime()}` + } + + // console.log('fileURL', fileURL) + + return fileURL +} + +export const useAssets = useRemoteAssets + +export default useRemoteAssets diff --git a/src/utils/index.js b/src/utils/index.js new file mode 100755 index 0000000..719b8fa --- /dev/null +++ b/src/utils/index.js @@ -0,0 +1,119 @@ +import _get from 'lodash/get' + +/** + * @desc 使用async await 进项进行延时操作 + * @param {*} time + */ +export function sleep(time = 1000) { + return new Promise((resolve) => { + setTimeout(() => resolve(true), time) + }) +} + +/** + * 使用indexof方法实现模糊查询 + * @param {Array} list 进行查询的数组 + * @param {String} keyWord 查询的关键词 + * @return {Array} 查询的结果 + */ +export function fuzzyQuery(list, keyWord, { keyName = '' } = {}) { + const arr = [] + for (let i = 0; i < list.length; i++) { + const str = keyName ? list[i][keyName] : list[i] + if (str.includes(keyWord)) { + arr.push(list[i]) + } + } + return arr +} + +/** + * 解构对象属性为可响应的计算属性 + * @param values 为对象时 对象的值作为计算属性的替换键名 + * @param {String} sourcePath 默认值为 '$Route.query' + * @returns {Object} Computeds + */ +export function mapComputed(keys = [], sourcePath = '$Route.query') { + const arr = Array.isArray(keys) + ? keys.map(name => [name, name]) + : Object.entries(keys) + const computeds = arr.reduce((obj, [name, replaceName]) => { + if (!replaceName) + replaceName = name + const formatPath = [...sourcePath.split('.'), name].join('.') + obj[replaceName] = function () { + return _get(this, formatPath) + } + return obj + }, {}) + return computeds +} + +/** + * @description 继承组件方法 + * @param {*} refName ref名称 + * @param {*} methodNames 需要继承的方法名列表 + * @returns + */ +export function inheritComponentMethods(refName, methodNames) { + const methods = {} + methodNames.forEach((name) => { + methods[name] = function (...params) { + return this.$refs[refName][name](...params) + } + }) + return methods +} + +// 字典映射 +export const mapDict = function ( + data, + { + childrenName = 'children', + keyName = 'value', + valueName = 'label', + mapValue, + } = {}, +) { + return data.reduce((obj, item) => { + const key = item[keyName] + const value = mapValue ? mapValue(item) : item[valueName] + obj[key] = value + if (Array.isArray(item[childrenName])) { + obj = { + ...obj, + ...mapDict(item[childrenName], { + childrenName, + keyName, + valueName, + mapValue, + }), + } + } + return obj + }, {}) +} + +/** + * 去除富文本标签 + * @param {*} value 富文本 + * @returns + */ +export function removeTag(value) { + return value + .replace(/<[^>]+>/g, '') + .replace(/ /g, '') + .replace(/“/g, '') + .replace(/”/g, '') +} + +/** + * 根据身份证号判断男女 + */ +export function getSexText(idCardNo) { + const gender = idCardNo.substr(-2, 1) + if (gender % 2 === 1) { + return '男' + } + return '女' +} diff --git a/src/utils/modals/index.js b/src/utils/modals/index.js new file mode 100755 index 0000000..713686c --- /dev/null +++ b/src/utils/modals/index.js @@ -0,0 +1 @@ +export * from './uniapp.js' diff --git a/src/utils/modals/uniapp.js b/src/utils/modals/uniapp.js new file mode 100755 index 0000000..d51b54c --- /dev/null +++ b/src/utils/modals/uniapp.js @@ -0,0 +1,91 @@ +/** + * @desc uni 弹窗 + * @param {*} content + * @param {*} param1 + */ +export function useDialog( + content, + { + title = '提示', + showCancelButton = false, + confirmButtonText = '确认', + cancelButtonText = '取消', + ...moreOptions + } = {}, +) { + return new Promise((resolve, reject) => { + uni.showModal({ + title, + content, + confirmText: confirmButtonText, + cancelText: cancelButtonText, + showCancel: showCancelButton, + ...moreOptions, + success({ cancel }) { + if (cancel) { + reject({ type: 'cancel' }) + } + + resolve({ type: 'confirm' }) + }, + }) + }) +} + +/** + * @desc uni 轻提示 + * @param {*} content 内容 + * @param {*} options 扩展参数 + */ +export function useToast( + content, + { + position = 'center', + duration = 1000, + overlay = true, + icon = 'none', + ...moreOptions + } = {}, +) { + if (!content) { + uni.hideToast() + return + } + + uni.showToast({ + title: content, + position, + duration, + mask: overlay, + icon, + ...moreOptions, + }) + + return new Promise((resolve) => { + setTimeout(() => { + resolve(uni) + }, duration) + }) +} + +/** + * @desc 显示或隐藏loading + * @param {*} content + * @param {*} options + */ +export function useLoading(content, { overlay = true, ...moreOptions } = {}) { + if (content && typeof content === 'boolean') { + content = '努力加载中...' + } + + if (!content) { + uni.hideLoading() + return + } + + uni.showLoading({ + title: content, + mask: overlay, + ...moreOptions, + }) +} diff --git a/src/utils/request/helper.js b/src/utils/request/helper.js new file mode 100755 index 0000000..7998bd3 --- /dev/null +++ b/src/utils/request/helper.js @@ -0,0 +1,52 @@ +export async function binaryParser(response, { dataKey = '_data' } = {}) { + return new Promise((resolve) => { + // console.log('response', response) + const data = response[dataKey] + let headers = response.headers + if (headers.toString() === '[object Headers]') { + headers = Object.fromEntries(headers.entries()) + // console.log('headers', headers) + } + + let resData = '' + let fileName + if (headers['content-disposition']) { + fileName = headers['content-disposition'].split(';')[1].split('=')[1] + } + const blob = data + if (!fileName) { + const errorData = new FileReader() + errorData.addEventListener('loadend', (data) => { + try { + resData = JSON.parse(data.target.result) + } + catch (e) { + resData = '' + } + resolve(resData) + }) + errorData.readAsText(blob) + } + else { + resData = { + fileName: window.decodeURIComponent(fileName), + blob: data, + } + const reader = new FileReader() + reader.readAsDataURL(blob) + reader.onload = (e) => { + const aEl = document.createElement('a') + aEl.download = window.decodeURIComponent(resData.fileName) + aEl.href = e.target.result + document.body.appendChild(aEl) + aEl.click() + document.body.removeChild(aEl) + resData = { + code: '0000', + message: '成功', + } + resolve(resData) + } + } + }) +} diff --git a/src/utils/request/index.js b/src/utils/request/index.js new file mode 100755 index 0000000..2d6bd8b --- /dev/null +++ b/src/utils/request/index.js @@ -0,0 +1,139 @@ +import { binaryParser } from './helper.js' +import request from './uni-network/index.js' +import store from '@/store/index.js' +import { responseSuccessCode } from '@/configs/request.js' +import { useLoading, useToast } from '@/utils/modals/index.js' + +// const userStore = store.user +// async function logout (message) { +// try { +// // console.log('logout', message) +// await useDialog(message, { +// title: '提示', +// showCancelButton: true, +// confirmButtonText: '重新登录', +// cancelButtonText: '退出', +// }) +// const userStore = store.useUserStore() +// userStore.logout() +// } +// catch (error) { +// wx.exitMiniProgram() +// } +// } + +export default request({ + onRequest ({ url, configs, bodyKey = 'body', queryKey = 'query' } = {}) { + // 解决什么都不传某些接口会报错的问题 + if (!configs[bodyKey]) { + configs[bodyKey] = {} + } + + // const body = configs[bodyKey] + + // 将 Headers类型对象转换为普通对象 + const headers + = configs.headers.toString() === '[object Headers]' + ? Object.fromEntries(configs.headers.entries()) + : configs.headers + + // 将 token 添加到请求头上 + const userStore = store.useUserStore() + const token = userStore.token + if (token) { + headers.token = token + } + + // 初始化数据加密 + // configs.aes = aesHelper({ headers, params: body }) + // const ret = configs.aes.encrypt() + // configs[bodyKey] = ret.params + // configs.headers = { + // ...headers, + // ...ret.headers, + // } + + // console.log('onRequest.url', url) + // console.log('onRequest.headers', configs.headers) + // console.log('onRequest.body', body) + // console.log('onRequest.query', configs[queryKey]) + // console.log('onRequest.configs', configs) + return configs + }, + onRequestError (error) { + useLoading(false) + console.log('onRequestError.error', error) + return Promise.reject(error) + }, + async onResponse ({ url, configs, response, dataKey = 'data' } = {}) { + // console.log('onResponse.response', response) + + // 文件二进制流响应全部数据(Tips:文件名在请求头中) + if (configs.responseType === 'blob') { + response[dataKey] = await binaryParser(response, { dataKey }) + } + + // 数据解密 + // response[dataKey] = configs.aes.decrypt({ data: response[dataKey] }) + + let data = response[dataKey] || {} + try { + typeof data === 'string' && (data = JSON.parse(data)) + } catch (error) { + } + + // 请求失败时终止 + if (!data?.code) { + useLoading(false) + return response + } + + // console.log('onResponse.data', response[dataKey]) + + // 校验 code + const { code } = data + const message = data.message || data.msg + + if (code === 201) { + const userStore = store.useUserStore() + userStore.logout() + } + else if (code != responseSuccessCode && message) { + useToast(message, { + type: 'warning', + duration: 3 * 1000, + }) + } + + response.data = { + ...data, + success: data.code == responseSuccessCode, + } + + return response + }, + async onResponseError ({ response, dataKey = 'data' } = {}) { + const data = response[dataKey] + const status = response.status + const statusText = response.statusText + + // console.log('onResponseError.response', response) + // console.log('onResponseError.data', response[dataKey]) + // console.log('onResponseError.status', response.status) + // console.log('onResponseError.statusText', response.statusText) + + // if (status === 401 || status === 403) { + // await logout(statusText) + // } + // else { + useLoading(false) + const message = statusText || data + useToast(message, { + type: 'error', + duration: 5 * 1000, + }) + + return Promise.reject(response) + // } + }, +}) diff --git a/src/utils/request/uni-network/core/index.js b/src/utils/request/uni-network/core/index.js new file mode 100755 index 0000000..fa99700 --- /dev/null +++ b/src/utils/request/uni-network/core/index.js @@ -0,0 +1,21 @@ +import request from '@uni-helper/uni-network' + +// import { responseSuccessCode } from '@/configs/request' + +// console.log('request.defaults', request.defaults) + +request.defaults.headers = { + ...(request.defaults?.headers || {}), +} + +export default { + ...request, + create: (options = {}) => + request.create({ + ...options, + baseUrl: options.baseURL, + validateStatus(...status) { + return status !== 500 + }, + }), +} diff --git a/src/utils/request/uni-network/index.js b/src/utils/request/uni-network/index.js new file mode 100755 index 0000000..3c778d2 --- /dev/null +++ b/src/utils/request/uni-network/index.js @@ -0,0 +1,174 @@ +import qs from 'qs' +import uniNetwork from './core/index' +import { baseURL, timeout } from '@/configs/request' + +export default ({ + onRequest, + onRequestError, + onResponse, + onResponseError, +} = {}) => { + // 创建请求服务 + const service = uniNetwork.create({ + baseURL, + headers: { + 'content-type': 'application/json;charset=utf-8', + }, + timeout, + xsrfHeaderName: 'token', + paramsSerializer: (params) => { + return Object.prototype.toString.call(params).includes('URLSearchParams') + ? params.toString() + : qs.stringify(params) + }, + }) + + // 请求拦截 + service.onRequest = (config) => { + // 解决 content-type 大小写覆盖问题 + if (config.headers['content-type']) { + config.headers['Content-Type'] = config.headers['content-type'] + delete config.headers['content-type'] + } + // 解决query无法传递数组的问题 + config.paramsSerializer = params => + qs.stringify(params, { + arrayFormat: 'repeat', + }) + + return onRequest({ + url: config.url, + configs: config, + headers: config.headers, + bodyKey: 'data', + queryKey: 'params', + }) + } + + // 请求失败拦截 + service.onRequestError = (error) => { + const { config } = error + return onRequestError({ + url: config?.url, + configs: config, + headers: Object.fromEntries(config.headers.entries()), + bodyKey: 'body', + queryKey: 'query', + error, + }) + } + + // 响应拦截 + service.onResponse = async (response) => { + const { config } = response + if (response?.errMsg === "request:fail ") { + return onResponse({ + url: config?.url, + configs: config || {}, + response: { ...response, data: { success: false } }, + dataKey: 'data', + }) + } else { + response = await onResponse({ + url: config?.url, + configs: config || {}, + response, + dataKey: 'data', + }) + } + + return response.data + } + + // 响应失败拦截 + service.onResponseError = error => + onResponseError({ + dataKey: 'data', + response: { + status: 500, + statusText: error.message, + }, + error, + }) + + service.interceptors.request.use(service.onRequest, service.onRequestError) + service.interceptors.response.use( + service.onResponse, + service.onResponseError, + ) + + /** + * 以表单形式提交数据 + * @param url + * @param params 要提交的参数(数据) + * @param useFormData 是否自动将 data 转为 FormData 格式 + * @returns {Promise} + */ + service.form = ( + url, + params, + { useFormData = true, paramsKey = 'data', ...options } = {}, + ) => { + if (useFormData) { + const formParams = new FormData() + Object.entries(params).forEach(([key, value]) => { + formParams.append(key, value) + }) + params = formParams + } + + return service({ + url, + [paramsKey]: params, + method: 'POST', + headers: { + 'Content-Type': 'multipart/form-data', + }, + ...options, + }) + } + + /** + * 以表单地址栏查询形式提交数据 + * @param url + * @param params 要提交的参数(数据) + * @param useQuery 是否自动将 data 转为 FormData 格式 + * @returns {Promise} + */ + service.query = ( + url, + params, + { useQuery = true, paramsKey = 'data', ...options } = {}, + ) => { + if (useQuery) { + const queryParams = qs.stringify(params) + params = queryParams + } + + return service({ + url, + [paramsKey]: params, + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + ...options, + }) + } + + /** + * 重写 get 别名以实现第二个参数可以直接传参 + * @param url + * @param params 要提交的参数(数据) + * @param useQuery 是否自动将 data 转为 FormData 格式 + * @returns {Promise} + */ + service.get = (url, params, { paramsKey = 'params', ...options } = {}) => + service({ + url, + method: 'GET', + [paramsKey]: params, + ...options, + }) + return service +} diff --git a/src/utils/showDictLabel.js b/src/utils/showDictLabel.js new file mode 100755 index 0000000..413c1f6 --- /dev/null +++ b/src/utils/showDictLabel.js @@ -0,0 +1,40 @@ +import { isString } from 'lodash-es' +import * as dictData from '@/configs/dict/index.js' + +/** + * @description 回显数据字典 + */ +export function showDictLabel(data, + value, + { + labelKey = 'dictLabel', + valueKey = 'dictValue', + childrenKey = 'children', + } = {}) { + const actions = [] + for (let index = 0; index < data.length; index++) { + const item = data[index] + if (item[valueKey] == `${value}`) { + actions.push(item[labelKey]) + break + } + const children = item[childrenKey] + if (children && children.length) { + const action = showDictLabel(children, value, { + labelKey, + valueKey, + childrenKey, + }) + if (action) { + actions.push(action) + break + } + } + } + return actions.join('') +} + +export default (param, value, options) => { + const data = isString(param) ? dictData[param] : param + return showDictLabel(data || {}, value, options) +} diff --git a/src/utils/storages/cookieStorage.js b/src/utils/storages/cookieStorage.js new file mode 100755 index 0000000..d2027bd --- /dev/null +++ b/src/utils/storages/cookieStorage.js @@ -0,0 +1,29 @@ +import jsCookie from 'js-cookie' + +/** + * 操作 Cookie + * @method set 设置 + * @method get 获取 + * @method remove 移除 + * @method clear 移除全部 + */ +export default { + // 设置 + set(key, val) { + jsCookie.set(key, JSON.stringify(val)) + }, + // 获取 + get(key) { + const json = jsCookie.get(key) + try { + return JSON.parse(json) + } + catch (error) { + return json + } + }, + // 移除 + remove(key) { + jsCookie.remove(key) + }, +} diff --git a/src/utils/storages/index.js b/src/utils/storages/index.js new file mode 100755 index 0000000..1c23c21 --- /dev/null +++ b/src/utils/storages/index.js @@ -0,0 +1,7 @@ +import defaultStorage from './uniStorage' + +// export { default as localStorage } from './localStorage' +// export { default as sessionStorage } from './sessionStorage' +// export { default as cookieStorage } from './cookieStorage' + +export default defaultStorage diff --git a/src/utils/storages/localStorage.js b/src/utils/storages/localStorage.js new file mode 100755 index 0000000..ea26c4e --- /dev/null +++ b/src/utils/storages/localStorage.js @@ -0,0 +1,31 @@ +/** + * window.localStorage + * @method set 设置 + * @method get 获取 + * @method remove 移除 + * @method clear 移除全部 + */ +export default { + // 设置 + set(key, val) { + window.localStorage.setItem(key, JSON.stringify(val)) + }, + // 获取 + get(key) { + const json = window.localStorage.getItem(key) + try { + return JSON.parse(json) + } + catch (error) { + return json + } + }, + // 移除 + remove(key) { + window.localStorage.removeItem(key) + }, + // 移除全部 + clear() { + window.localStorage.clear() + }, +} diff --git a/src/utils/storages/sessionStorage.js b/src/utils/storages/sessionStorage.js new file mode 100755 index 0000000..3d762f6 --- /dev/null +++ b/src/utils/storages/sessionStorage.js @@ -0,0 +1,31 @@ +/** + * window.sessionStorage + * @method set 设置 + * @method get 获取 + * @method remove 移除 + * @method clear 移除全部 + */ +export default { + // 设置 + set(key, val) { + window.sessionStorage.setItem(key, JSON.stringify(val)) + }, + // 获取 + get(key) { + const json = window.sessionStorage.getItem(key) + try { + return JSON.parse(json) + } + catch (error) { + return json + } + }, + // 移除 + remove(key) { + window.sessionStorage.removeItem(key) + }, + // 移除全部 + clear() { + window.sessionStorage.clear() + }, +} diff --git a/src/utils/storages/uniStorage.js b/src/utils/storages/uniStorage.js new file mode 100755 index 0000000..8a20e00 --- /dev/null +++ b/src/utils/storages/uniStorage.js @@ -0,0 +1,25 @@ +/** + * 通用存储 store + * @method set 设置永久缓存 + * @method get 获取永久缓存 + * @method remove 移除永久缓存 + * @method clear 移除全部永久缓存 + */ +export default { + // 设置永久缓存 + set(key, value) { + uni.setStorageSync(key, value) + }, + // 获取永久缓存 + get(key) { + return uni.getStorageSync(key) + }, + // 移除永久缓存 + remove(key) { + uni.removeStorageSync(key) + }, + // 移除全部永久缓存 + clear() { + uni.clearStorageSync() + }, +} diff --git a/src/utils/token.js b/src/utils/token.js new file mode 100755 index 0000000..3d68175 --- /dev/null +++ b/src/utils/token.js @@ -0,0 +1,20 @@ +import storage from '@/utils/storages/index.js' + +export function setToken (data) { + storage.set('token', data) +} + +export const getToken = () => storage.get('token') + +export function removeToken () { + storage.remove('userInfo') +} +export function setUserInfo (data) { + storage.set('userInfo', data) +} + +export const getUserInfo = () => storage.get('userInfo') || {} + +export function removeUserInfo () { + storage.remove('userInfo') +} diff --git a/src/utils/tree.js b/src/utils/tree.js new file mode 100755 index 0000000..9c2da44 --- /dev/null +++ b/src/utils/tree.js @@ -0,0 +1,196 @@ +/** + * 与树处理相关的函数 + */ +import { cloneDeep, find } from 'lodash-es' + +// 数组根据函数进行排序 +function sortData(data, sortFun) { + data.sort(sortFun) +} + +/** + * 生成排序函数 + * @param {String} sortField 排序字段 + * @param { Boolean} asc 是否正序 + * @returns {Function} 排序函数 + */ +function generateSortFn(sortField, asc) { + return (a, b) => { + const valueA = a[sortField] + const valueB = b[sortField] + if (valueA > valueB) { + if (asc) { + return 1 + } + return -1 + } + if (asc) { + return -1 + } + return 1 + } +} + +/** + * 数组结构转化成树结构 + * @returns {Array} + */ +export const arrayToTree = function ( + data = [], + invalId = [], + id = 'id', + parentId = 'parentId', +) { + // 结果 + const result = [] + // 复制数据 + const dataTemp = cloneDeep(data) + + dataTemp.forEach((item) => { + // 添加children + if (!item.children) { + item.children = [] + } + + // 去掉无效节点 + if (invalId.includes(item[id])) + return + + // parentUuid值 + const parentIdValue = item[parentId] + + // 不存在parent值 + if (!parentIdValue) { + item._level = 1 + result.push(item) + } + else { + // 父对象 + const parent = find(dataTemp, node => node[id] === parentIdValue) + // 不存在父对象 + if (!parent) { + item._level = 1 + result.push(item) + return + } + if (!parent.children) { + parent._level = parent._level ? parent._level : 1 + parent.children = [] + } + // 添加到父对象children + item._level = parent._level + 1 + parent.children.push(item) + } + }) + return result +} + +/** + * 查询问题分类路径数据 + * @param {*} id + * @param {*} data + */ +export function arrayTreePathData(id, data) { + const item = { + problemCategoryLevelId: [], + problemCategoryLevelIds: [], + } + data.forEach((itema) => { + itema.children.forEach((itemb) => { + itemb.children.forEach((itemc) => { + itemc.children.forEach((itemd) => { + if (itemd.id === id) { + item.problemCategoryLevelIds = [itema.id, itemb.id, itemc.id] + item.problemCategoryLevelId = [itema.name, itemb.name, itemc.name] + } + }) + }) + }) + }) + return item +} + +/** + * 对树进行排序(通过自定义函数) + * @param {Array} treeData 树 + * @param {Function} sortFun 排序函数 + * @returns {Array} + */ +export const sortTreeByFunction = function (treeData, sortFun) { + sortData(treeData, sortFun) + treeData.forEach((item) => { + const children = item.children + if (children && children.length > 0) { + sortData(children, sortFun) + sortTreeByFunction(children, sortFun) + } + }) + return treeData +} + +/** + * 对树进行排序(通过字段) + * @param {Array} treeData 树 + * @param {String} sortField 排序字段 + * @param { Boolean} asc 是否正序 + * @returns {Array} 排序树 + */ +export const sortTreeByField = function (treeData, sortField, asc = true) { + return sortTreeByFunction(treeData, generateSortFn(sortField, asc)) +} + +/** + * 树的最后一级转化为数组 + * @param {Array} treeData 树 + * @returns {Array} 数组 + */ +export const treeFinalToArray = function (treeData) { + let result = [] + Array.from(treeData).forEach((record) => { + if (record.childNodes && record.childNodes.length > 0) { + const children = treeFinalToArray(record.childNodes) + result = result.concat(children) + } + else { + result.push(record.data) + } + }) + return result +} + +/** + * 树转化数组 + * @param {Array} treeData 树 + * @param {String} childsKey 树 + * @returns {Array} 数组 + */ +export const treeToArray = function (treeData = [], childsKey = 'children') { + let result = [] + Array.from(treeData).forEach((record) => { + result.push(record) + if (record[childsKey] && record[childsKey].length > 0) { + const children = treeToArray(record[childsKey], childsKey) + result = result.concat(children) + } + }) + return result +} + +/** + * 树对象转化数组 + * @param {Object} treeObject 树 + * @param {String} childKey 树 + * @returns {Array} 数组 + */ +export const treeObjToArray = function ( + treeObject = {}, + childKey = 'children', +) { + let result = [] + result.push(treeObject) + if (treeObject[childKey]) { + const children = treeObjToArray(treeObject[childKey], childKey) + result = result.concat(children) + } + return result +} diff --git a/src/utils/treeSimple.js b/src/utils/treeSimple.js new file mode 100755 index 0000000..71d03c6 --- /dev/null +++ b/src/utils/treeSimple.js @@ -0,0 +1,243 @@ +import { omit } from 'lodash-es' + +const defaultOptions = { + key: 'id', // 主键 + parentKey: 'parentId', // 父节点主键 + children: 'children', // 子节点 + isTree: false, // 源数据是否是树结构 +} + +/** + * 将树型结构数据转换成一维数组 + * @param treeData + */ +export function tree2List(treeData, options = {}) { + const props = { + ...defaultOptions, + ...options, + } + let listData = [] + treeData.forEach((item) => { + listData.push(item) + const children = item[props.children] + if (children && children.length > 0) { + listData = [...listData, ...tree2List(children, props)] + } + }) + return listData +} + +/** + * 将一维数组数据转换成树型结构 + * @param listData + */ +export function list2Tree(listData, options = {}) { + const props = { + ...defaultOptions, + ...options, + } + + const obj = {} + // obj对象的key为listData中每一个对象的id,value为每一个对象 + listData.forEach((item) => { + obj[item[props.key]] = item + }) + + // 最终要返回的树型数组 + const treeData = [] + + // 对原一维数组进行遍历 + for (let i = 0; i < listData.length; i++) { + const item = listData[i] // 原一维数组中的每一项 + const parent = obj[item[props.parentKey]] // 从之前保存的对象中取出当前项的父项 + if (parent) { + if (parent[props.children]) { + parent[props.children].push(item) // 父项的children加入子项 + } + else { + parent[props.children] = [] + parent[props.children].push(item) + } + } + else { + treeData.push(item) // 否则直接将当前项加入最后的树状数组作为根(因为此项没有父项) + } + } + return treeData +} + +/** + * 寻找指定子节点 + * @param {number|string} key + * @param treeData + * @param props + */ +export function getNodeByKey(key, treeData, options = {}) { + const props = { + ...defaultOptions, + ...options, + } + + if (!treeData || treeData.length === 0) { + return null + } + + for (let i = 0; i < treeData.length; i++) { + const node = treeData[i] + if (node[props.key] === key) { + return node + } + const children = node[props.children] + if (children && children.length > 0) { + const targetNode = getNodeByKey(key, children, props) + if (targetNode) { + return targetNode + } + } + } + return null +} + +/** + * 获取节点下的所有子节点 + * @param {number|string} key + * @param treeData + * @param props + */ +export function getChildrenByKey(key, treeData, options = {}) { + const props = { + ...defaultOptions, + ...options, + } + const targetNode = getNodeByKey(key, treeData, props) + if (!targetNode) { + return [] + } + const children = targetNode[props.children] + if (children && children.length > 0) { + return tree2List(children, props) + } + return [] +} + +/** + * 遍历每个树节点 + * @param treeData + * @param callback + * @param props + */ +export function forEachNode(treeData, callback, options = {}) { + if (!treeData) + return [] + + const props = { + ...defaultOptions, + ...options, + } + + treeData.forEach((item) => { + callback(item, treeData) + const children = item[props.children] + forEachNode(children, callback, props) + }) +} + +/** + * map 每个树节点 + * @param treeData + * @param callback + * @param props + */ +export function mapNode(treeData, callback, options = {}) { + if (!treeData) + return [] + + const props = { + ...defaultOptions, + ...options, + } + + return treeData.map(item => ({ + ...callback(item, treeData), + children: mapNode(item[props.children], callback, props), + })) +} + +/** + * filter 每个树节点 + * @param treeData + * @param callback + * @param props + */ +export function filterTree(treeData, callback, options = {}) { + if (!treeData) + return [] + + const props = { + ...defaultOptions, + ...options, + } + + const selectedNodes = [] + forEachNode( + treeData, + (item) => { + if (callback(item, treeData)) { + selectedNodes.push(omit(item, props.children)) + } + }, + props, + ) + + const value = list2Tree(selectedNodes, props) + + return value +} + +/** + * 获取所有父节点 + * @param {number|string} key + * @param data 可以是 listData 也可以是 treeData + * @param props + */ +export function getParentNodes(key, data, options = {}) { + if (!key && key !== 0) { + return [] + } + + const props = { + ...defaultOptions, + immediate: false, // 仅获取直接父级 + ...options, + } + + const listData = props.isTree ? tree2List(data, props) : data + + const targetNode = listData.find(item => item[props.key] === key) + + if (!targetNode) { + return [] + } + + const parentNodeIndex = listData.findIndex( + item => item[props.key] === targetNode[props.parentKey], + ) + + if (parentNodeIndex === -1) { + return [] + } + + const parentNode = listData[parentNodeIndex] + + if (props.immediate) { + return [parentNode] + } + + return [ + ...getParentNodes(parentNode[props.key], listData, { + ...props, + isTree: false, + }), + parentNode, + ] +} diff --git a/src/utils/uni-router/helper.js b/src/utils/uni-router/helper.js new file mode 100755 index 0000000..c73c665 --- /dev/null +++ b/src/utils/uni-router/helper.js @@ -0,0 +1,175 @@ +import { cloneDeep, isArray, isString, omit } from 'lodash-es' +import qs from 'qs' +import pages from '@/pages.json' + +/** + * 路由模型 + * @param {string} methodName 路由跳转方法名 + * @param {object} options 路由配置 + * @returns + */ +export function routerModel( + methodName, + { pathKey = 'path', params, router, pathMap = {} } = {}, +) { + // console.log('params', params) + + let options + if (isString(params)) { + const [path, rawQuery] = params.split('?') + const query = qs.parse(rawQuery) || {} + options = { path, query } + } + else { + options = { ...params } + } + // console.log('options', options) + + const path = pathMap[options.path || '/'] + + if (!path) { + console.error(`没有找到该路由,请检查是否正确配置 "${options.path}"`) + return + } + + methodName = hasTabBar(pages, path) ? 'switchTab' : methodName + + // console.log('pathMap', pathMap) + // console.log('path', path) + // console.log('methodName', methodName) + + return router[methodName]({ + ...omit(options, 'path'), + [pathKey]: path, + query: options.query || {}, + }) +} + +/** + * 检查指定的页面路径是否为 tabbar类型 + * @param {*} pages 页面配置 + * @param {*} path 页面路径 + * @returns + */ +export function hasTabBar(pages, path) { + const list = pages?.tabBar?.list || [] + const listMap = list.reduce((obj, item) => { + obj[`/${item.pagePath}`] = true + return obj + }, {}) + + return !!listMap[path] +} + +/** + * 将uniapp路由跳转方式 转换为VueRouer方式 + * @param {object} router + * @returns {object} + */ +export function aliasTransformer(router, { addRoot = false } = {}) { + const routes = router.options.routes || [] + const pathMap = resolvePagePath(routes, { addRoot }) + return { + push: params => + routerModel('navigateTo', { + params, + router, + pathMap, + addRoot, + }), + replace: params => + routerModel('redirectTo', { + params, + router, + pathMap, + addRoot, + }), + replaceAll: params => + routerModel('reLaunch', { + params, + router, + pathMap, + addRoot, + }), + back: (delta = 1, params) => + router.navigateBack({ + params, + delta, + }), + } +} + +/** + * 对页面配置进行数据整理 以适配分包策略 + * @param {*} pages 页面配置 + * @returns + */ +export function resolvePages(pages, { addRoot = false } = {}) { + pages = cloneDeep(pages) + const value = pages?.pages || [] + + const subPackages = (pages.subPackages || []).reduce((arr, item) => { + const root = item.root + arr.push( + ...item.pages.map(item_1 => ({ + ...item_1, + path: `${root}/${item_1.path}`, + })), + ) + return arr + }, []) + // console.log('subPackages', subPackages) + value.push(...subPackages) + + if (addRoot) { + value.forEach((item) => { + item.path = `/${item.path}` + }) + } + + // console.log('resolvePages.value', value) + + return value +} + +/** + * 获取根路由页面路径值 + * @param {*} pages 页面配置 + * @returns + */ +export const getRootPagePath = (pages) => { + pages = isArray(pages) ? pages : pages?.pages || [] + const value = pages.find(item => item.type === 'home')?.path || '' + return value +} + +/** + * 对页面路径进行转换映射 + * @param {*} pages 页面配置 + * @returns + */ +export function resolvePagePath( + pages, + { shortcutName = 'aliasPath', addRoot = false } = {}, +) { + const pathList = isArray(pages) ? pages : resolvePages(pages, { addRoot }) + const pathMap = pathList.reduce((obj, item) => { + const path = item.path + + if (item[shortcutName]) { + obj[item[shortcutName]] = path + } + obj[path] = path + + return obj + }, {}) + + const value = { + ...pathMap, + '/': getRootPagePath(pages), + } + + // console.log('resolvePagePath.value', value) + + return value +} diff --git a/src/utils/uni-router/index.js b/src/utils/uni-router/index.js new file mode 100755 index 0000000..25e1b46 --- /dev/null +++ b/src/utils/uni-router/index.js @@ -0,0 +1,49 @@ +import { isH5 } from '@uni-helper/uni-env' +import { createRouter as _createRouter } from 'uniapp-router-next' +import { aliasTransformer, resolvePages } from './helper.js' +import { homePage } from '@/configs/index.js' + +export { useRouter, useRoute } from 'uniapp-router-next' + +export * from './helper.js' + +export function createRouter ({ pages, addRoutes = [], ...options } = {}) { + const routes = [...resolvePages(pages, { addRoot: true }), ...addRoutes] + if (isH5) { + routes.unshift({ + ...routes.find(item => item.path.includes(homePage)), + path: '/', + }) + } + + // console.log('createRouter.routes', routes) + + const router = _createRouter({ + ...options, + platform: process.env.UNI_PLATFORM, + routes, + debug: true, + }) + + const alias = aliasTransformer(router, { addRoot: true }) + Object.assign(router, { ...alias }) + + // Extend install methods + const defaultInstall = router.install + router.install = (app) => { + defaultInstall(app) + app.config.globalProperties.$Router = { + ...router, + ...alias, + } + + Object.defineProperty(app.config.globalProperties, '$Route', { + enumerable: true, + get () { + return router.currentRoute.value + }, + }) + } + + return router +} diff --git a/src/utils/uni-router/middleware.js b/src/utils/uni-router/middleware.js new file mode 100755 index 0000000..4f12101 --- /dev/null +++ b/src/utils/uni-router/middleware.js @@ -0,0 +1,20 @@ +/** + * 将路由守卫包装为中间件 + */ +export function defineMiddleware(name, handler, { router, app } = {}) { + router.beforeEach((to, from, next) => { + const middleware = to.meta.middleware || [] + if (!middleware.includes(name)) { + next() + } + else { + handler( + { + ...router, + beforeEach: func => func(to, from, next), + }, + { app }, + ) + } + }) +} diff --git a/src/utils/util.ts b/src/utils/util.ts new file mode 100755 index 0000000..d4e3b85 --- /dev/null +++ b/src/utils/util.ts @@ -0,0 +1,108 @@ +import { useToast } from '@/utils/modals' +export function loadJs(src: string) { + return new Promise((resolve, reject) => { + const script = document.createElement('script') + script.type = 'text/javascript' + script.src = src + document.body.appendChild(script) + script.onload = () => { + resolve(true) + } + script.onerror = () => { + reject() + } + }) +} + +/** + * 处理微信重定向地址 + * @param appid wx公众号id + * @param href 重定向地址 + * @param scope 微信授权 snsapi_userinfo: 头像等信息授权 snsapi_base: jscode授权 + * @returns 微信授权地址 + */ +export function handleWxRedict( + appid: string, + href: string, + scope: string, + state?: any, +): string { + console.log( + `%c>_> appid=>`, + 'color:#ff7b54;font-size:16px;', + appid, + href, + scope, + state, + ) + if (state) { + return `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${encodeURIComponent( + href, + )}&response_type=code&scope=${scope}&state=${encodeURIComponent( + state, + )}#wechat_redirect` + } else { + return `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${encodeURIComponent( + href, + )}&response_type=code&scope=${scope}#wechat_redirect` + } +} + +function addZero(num: number) { + return num >= 10 ? String(num) : '0' + num +} + +/** + * 秒数时间转换 + * @param seconds 秒数 + * @param format 时间格式 + * @returns HH:mm:ss时间格式 + */ +export function secondFormat(seconds: number, format = 'h'): string { + const hour: string = addZero(Math.floor(seconds / 60 / 60)) + const minute: string = addZero(Math.floor(seconds / 60) % 60) + const second: string = addZero(seconds % 60) + if (format === 'h') { + return `${hour}:${minute}:${second}` + } else if (format === 'm') { + return `${minute}:${second}` + } else { + return `${second}` + } +} + +export function getQueryString(name: string) { + const queryList = window.location.href.split('?') + if (queryList.length < 2) { + return null + } + const getqyinfo: any = queryList[queryList.length - 1] //qycode=1001&qyname=%E4%BC%81%E4%B8%9A%E5%BF%99 截取到参数部分 + const getqys: any = new URLSearchParams('?' + getqyinfo) + return getqys.get(name) +} + +export function initClipboard(name: any) { + if (name === null) { + return + } + const inputElement = document.createElement('input') + inputElement.value = name + document.body.appendChild(inputElement) + inputElement.select() + document.execCommand('copy') + inputElement.remove() + useToast('复制成功') +} + +export function thousandthTranslate(num: any) { + if (!num) { + return '0.00' + } + if (String(num).includes('.')) { + if (String(num).split('.')[1].length === 1) { + return Number(num).toLocaleString() + '0' + } + return Number(num).toLocaleString() + } + return Number(num).toLocaleString() + '.00' +} diff --git a/src/wxcomponents/vant-weapp/action-sheet/index.d.ts b/src/wxcomponents/vant-weapp/action-sheet/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/action-sheet/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/action-sheet/index.js b/src/wxcomponents/vant-weapp/action-sheet/index.js new file mode 100755 index 0000000..aee6999 --- /dev/null +++ b/src/wxcomponents/vant-weapp/action-sheet/index.js @@ -0,0 +1,71 @@ +import { VantComponent } from '../common/component'; +import { button } from '../mixins/button'; +VantComponent({ + classes: ['list-class'], + mixins: [button], + props: { + show: Boolean, + title: String, + cancelText: String, + description: String, + round: { + type: Boolean, + value: true, + }, + zIndex: { + type: Number, + value: 100, + }, + actions: { + type: Array, + value: [], + }, + overlay: { + type: Boolean, + value: true, + }, + closeOnClickOverlay: { + type: Boolean, + value: true, + }, + closeOnClickAction: { + type: Boolean, + value: true, + }, + safeAreaInsetBottom: { + type: Boolean, + value: true, + }, + }, + methods: { + onSelect(event) { + const { index } = event.currentTarget.dataset; + const { actions, closeOnClickAction, canIUseGetUserProfile } = this.data; + const item = actions[index]; + if (item) { + this.$emit('select', item); + if (closeOnClickAction) { + this.onClose(); + } + if (item.openType === 'getUserInfo' && canIUseGetUserProfile) { + wx.getUserProfile({ + desc: item.getUserProfileDesc || ' ', + complete: (userProfile) => { + this.$emit('getuserinfo', userProfile); + }, + }); + } + } + }, + onCancel() { + this.$emit('cancel'); + }, + onClose() { + this.$emit('close'); + }, + onClickOverlay() { + this.$emit('click-overlay'); + this.onClose(); + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/action-sheet/index.json b/src/wxcomponents/vant-weapp/action-sheet/index.json new file mode 100755 index 0000000..19bf989 --- /dev/null +++ b/src/wxcomponents/vant-weapp/action-sheet/index.json @@ -0,0 +1,8 @@ +{ + "component": true, + "usingComponents": { + "van-icon": "../icon/index", + "van-popup": "../popup/index", + "van-loading": "../loading/index" + } +} diff --git a/src/wxcomponents/vant-weapp/action-sheet/index.wxml b/src/wxcomponents/vant-weapp/action-sheet/index.wxml new file mode 100755 index 0000000..d59a45d --- /dev/null +++ b/src/wxcomponents/vant-weapp/action-sheet/index.wxml @@ -0,0 +1,69 @@ + + + + + {{ title }} + + + + {{ description }} + + + + + + + + + + {{ cancelText }} + + + diff --git a/src/wxcomponents/vant-weapp/action-sheet/index.wxss b/src/wxcomponents/vant-weapp/action-sheet/index.wxss new file mode 100755 index 0000000..eedd361 --- /dev/null +++ b/src/wxcomponents/vant-weapp/action-sheet/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-action-sheet{color:var(--action-sheet-item-text-color,#323233);max-height:var(--action-sheet-max-height,90%)!important}.van-action-sheet__cancel,.van-action-sheet__item{background-color:var(--action-sheet-item-background,#fff);font-size:var(--action-sheet-item-font-size,16px);line-height:var(--action-sheet-item-line-height,22px);padding:14px 16px;text-align:center}.van-action-sheet__cancel--hover,.van-action-sheet__item--hover{background-color:#f2f3f5}.van-action-sheet__cancel:after,.van-action-sheet__item:after{border-width:0}.van-action-sheet__cancel{color:var(--action-sheet-cancel-text-color,#646566)}.van-action-sheet__gap{background-color:var(--action-sheet-cancel-padding-color,#f7f8fa);display:block;height:var(--action-sheet-cancel-padding-top,8px)}.van-action-sheet__item--disabled{color:var(--action-sheet-item-disabled-text-color,#c8c9cc)}.van-action-sheet__item--disabled.van-action-sheet__item--hover{background-color:var(--action-sheet-item-background,#fff)}.van-action-sheet__subname{color:var(--action-sheet-subname-color,#969799);font-size:var(--action-sheet-subname-font-size,12px);line-height:var(--action-sheet-subname-line-height,20px);margin-top:var(--padding-xs,8px)}.van-action-sheet__header{font-size:var(--action-sheet-header-font-size,16px);font-weight:var(--font-weight-bold,500);line-height:var(--action-sheet-header-height,48px);text-align:center}.van-action-sheet__description{color:var(--action-sheet-description-color,#969799);font-size:var(--action-sheet-description-font-size,14px);line-height:var(--action-sheet-description-line-height,20px);padding:20px var(--padding-md,16px);text-align:center}.van-action-sheet__close{color:var(--action-sheet-close-icon-color,#c8c9cc);font-size:var(--action-sheet-close-icon-size,22px)!important;line-height:inherit!important;padding:var(--action-sheet-close-icon-padding,0 16px);position:absolute!important;right:0;top:0}.van-action-sheet__loading{display:flex!important} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/area/index.d.ts b/src/wxcomponents/vant-weapp/area/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/area/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/area/index.js b/src/wxcomponents/vant-weapp/area/index.js new file mode 100755 index 0000000..9cf1edd --- /dev/null +++ b/src/wxcomponents/vant-weapp/area/index.js @@ -0,0 +1,220 @@ +import { VantComponent } from '../common/component'; +import { pickerProps } from '../picker/shared'; +import { requestAnimationFrame } from '../common/utils'; +const EMPTY_CODE = '000000'; +VantComponent({ + classes: ['active-class', 'toolbar-class', 'column-class'], + props: Object.assign(Object.assign({}, pickerProps), { showToolbar: { + type: Boolean, + value: true, + }, value: { + type: String, + observer(value) { + this.code = value; + this.setValues(); + }, + }, areaList: { + type: Object, + value: {}, + observer: 'setValues', + }, columnsNum: { + type: null, + value: 3, + }, columnsPlaceholder: { + type: Array, + observer(val) { + this.setData({ + typeToColumnsPlaceholder: { + province: val[0] || '', + city: val[1] || '', + county: val[2] || '', + }, + }); + }, + } }), + data: { + columns: [{ values: [] }, { values: [] }, { values: [] }], + typeToColumnsPlaceholder: {}, + }, + mounted() { + requestAnimationFrame(() => { + this.setValues(); + }); + }, + methods: { + getPicker() { + if (this.picker == null) { + this.picker = this.selectComponent('.van-area__picker'); + } + return this.picker; + }, + onCancel(event) { + this.emit('cancel', event.detail); + }, + onConfirm(event) { + const { index } = event.detail; + let { value } = event.detail; + value = this.parseValues(value); + this.emit('confirm', { value, index }); + }, + emit(type, detail) { + detail.values = detail.value; + delete detail.value; + this.$emit(type, detail); + }, + parseValues(values) { + const { columnsPlaceholder } = this.data; + return values.map((value, index) => { + if (value && + (!value.code || value.name === columnsPlaceholder[index])) { + return Object.assign(Object.assign({}, value), { code: '', name: '' }); + } + return value; + }); + }, + onChange(event) { + var _a; + const { index, picker, value } = event.detail; + this.code = value[index].code; + (_a = this.setValues()) === null || _a === void 0 ? void 0 : _a.then(() => { + this.$emit('change', { + picker, + values: this.parseValues(picker.getValues()), + index, + }); + }); + }, + getConfig(type) { + const { areaList } = this.data; + return (areaList && areaList[`${type}_list`]) || {}; + }, + getList(type, code) { + if (type !== 'province' && !code) { + return []; + } + const { typeToColumnsPlaceholder } = this.data; + const list = this.getConfig(type); + let result = Object.keys(list).map((code) => ({ + code, + name: list[code], + })); + if (code != null) { + // oversea code + if (code[0] === '9' && type === 'city') { + code = '9'; + } + result = result.filter((item) => item.code.indexOf(code) === 0); + } + if (typeToColumnsPlaceholder[type] && result.length) { + // set columns placeholder + const codeFill = type === 'province' + ? '' + : type === 'city' + ? EMPTY_CODE.slice(2, 4) + : EMPTY_CODE.slice(4, 6); + result.unshift({ + code: `${code}${codeFill}`, + name: typeToColumnsPlaceholder[type], + }); + } + return result; + }, + getIndex(type, code) { + let compareNum = type === 'province' ? 2 : type === 'city' ? 4 : 6; + const list = this.getList(type, code.slice(0, compareNum - 2)); + // oversea code + if (code[0] === '9' && type === 'province') { + compareNum = 1; + } + code = code.slice(0, compareNum); + for (let i = 0; i < list.length; i++) { + if (list[i].code.slice(0, compareNum) === code) { + return i; + } + } + return 0; + }, + setValues() { + const picker = this.getPicker(); + if (!picker) { + return; + } + let code = this.code || this.getDefaultCode(); + const provinceList = this.getList('province'); + const cityList = this.getList('city', code.slice(0, 2)); + const stack = []; + const indexes = []; + const { columnsNum } = this.data; + if (columnsNum >= 1) { + stack.push(picker.setColumnValues(0, provinceList, false)); + indexes.push(this.getIndex('province', code)); + } + if (columnsNum >= 2) { + stack.push(picker.setColumnValues(1, cityList, false)); + indexes.push(this.getIndex('city', code)); + if (cityList.length && code.slice(2, 4) === '00') { + [{ code }] = cityList; + } + } + if (columnsNum === 3) { + stack.push(picker.setColumnValues(2, this.getList('county', code.slice(0, 4)), false)); + indexes.push(this.getIndex('county', code)); + } + return Promise.all(stack) + .catch(() => { }) + .then(() => picker.setIndexes(indexes)) + .catch(() => { }); + }, + getDefaultCode() { + const { columnsPlaceholder } = this.data; + if (columnsPlaceholder.length) { + return EMPTY_CODE; + } + const countyCodes = Object.keys(this.getConfig('county')); + if (countyCodes[0]) { + return countyCodes[0]; + } + const cityCodes = Object.keys(this.getConfig('city')); + if (cityCodes[0]) { + return cityCodes[0]; + } + return ''; + }, + getValues() { + const picker = this.getPicker(); + if (!picker) { + return []; + } + return this.parseValues(picker.getValues().filter((value) => !!value)); + }, + getDetail() { + const values = this.getValues(); + const area = { + code: '', + country: '', + province: '', + city: '', + county: '', + }; + if (!values.length) { + return area; + } + const names = values.map((item) => item.name); + area.code = values[values.length - 1].code; + if (area.code[0] === '9') { + area.country = names[1] || ''; + area.province = names[2] || ''; + } + else { + area.province = names[0] || ''; + area.city = names[1] || ''; + area.county = names[2] || ''; + } + return area; + }, + reset(code) { + this.code = code || ''; + return this.setValues(); + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/area/index.json b/src/wxcomponents/vant-weapp/area/index.json new file mode 100755 index 0000000..a778e91 --- /dev/null +++ b/src/wxcomponents/vant-weapp/area/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "van-picker": "../picker/index" + } +} diff --git a/src/wxcomponents/vant-weapp/area/index.wxml b/src/wxcomponents/vant-weapp/area/index.wxml new file mode 100755 index 0000000..3a437b7 --- /dev/null +++ b/src/wxcomponents/vant-weapp/area/index.wxml @@ -0,0 +1,20 @@ + + + diff --git a/src/wxcomponents/vant-weapp/area/index.wxs b/src/wxcomponents/vant-weapp/area/index.wxs new file mode 100755 index 0000000..07723c1 --- /dev/null +++ b/src/wxcomponents/vant-weapp/area/index.wxs @@ -0,0 +1,8 @@ +/* eslint-disable */ +function displayColumns(columns, columnsNum) { + return columns.slice(0, +columnsNum); +} + +module.exports = { + displayColumns: displayColumns, +}; diff --git a/src/wxcomponents/vant-weapp/area/index.wxss b/src/wxcomponents/vant-weapp/area/index.wxss new file mode 100755 index 0000000..99694d6 --- /dev/null +++ b/src/wxcomponents/vant-weapp/area/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss'; \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/button/index.d.ts b/src/wxcomponents/vant-weapp/button/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/button/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/button/index.js b/src/wxcomponents/vant-weapp/button/index.js new file mode 100755 index 0000000..0e3c134 --- /dev/null +++ b/src/wxcomponents/vant-weapp/button/index.js @@ -0,0 +1,64 @@ +import { VantComponent } from '../common/component'; +import { button } from '../mixins/button'; +import { canIUseFormFieldButton } from '../common/version'; +const mixins = [button]; +if (canIUseFormFieldButton()) { + mixins.push('wx://form-field-button'); +} +VantComponent({ + mixins, + classes: ['hover-class', 'loading-class'], + data: { + baseStyle: '', + }, + props: { + formType: String, + icon: String, + classPrefix: { + type: String, + value: 'van-icon', + }, + plain: Boolean, + block: Boolean, + round: Boolean, + square: Boolean, + loading: Boolean, + hairline: Boolean, + disabled: Boolean, + loadingText: String, + customStyle: String, + loadingType: { + type: String, + value: 'circular', + }, + type: { + type: String, + value: 'default', + }, + dataset: null, + size: { + type: String, + value: 'normal', + }, + loadingSize: { + type: String, + value: '20px', + }, + color: String, + }, + methods: { + onClick(event) { + this.$emit('click', event); + const { canIUseGetUserProfile, openType, getUserProfileDesc, lang, } = this.data; + if (openType === 'getUserInfo' && canIUseGetUserProfile) { + wx.getUserProfile({ + desc: getUserProfileDesc || ' ', + lang: lang || 'en', + complete: (userProfile) => { + this.$emit('getuserinfo', userProfile); + }, + }); + } + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/button/index.json b/src/wxcomponents/vant-weapp/button/index.json new file mode 100755 index 0000000..e00a588 --- /dev/null +++ b/src/wxcomponents/vant-weapp/button/index.json @@ -0,0 +1,7 @@ +{ + "component": true, + "usingComponents": { + "van-icon": "../icon/index", + "van-loading": "../loading/index" + } +} diff --git a/src/wxcomponents/vant-weapp/button/index.wxml b/src/wxcomponents/vant-weapp/button/index.wxml new file mode 100755 index 0000000..e7f60f1 --- /dev/null +++ b/src/wxcomponents/vant-weapp/button/index.wxml @@ -0,0 +1,56 @@ + + + + diff --git a/src/wxcomponents/vant-weapp/button/index.wxs b/src/wxcomponents/vant-weapp/button/index.wxs new file mode 100755 index 0000000..8b649fe --- /dev/null +++ b/src/wxcomponents/vant-weapp/button/index.wxs @@ -0,0 +1,39 @@ +/* eslint-disable */ +var style = require('../wxs/style.wxs'); + +function rootStyle(data) { + if (!data.color) { + return data.customStyle; + } + + var properties = { + color: data.plain ? data.color : '#fff', + background: data.plain ? null : data.color, + }; + + // hide border when color is linear-gradient + if (data.color.indexOf('gradient') !== -1) { + properties.border = 0; + } else { + properties['border-color'] = data.color; + } + + return style([properties, data.customStyle]); +} + +function loadingColor(data) { + if (data.plain) { + return data.color ? data.color : '#c9c9c9'; + } + + if (data.type === 'default') { + return '#c9c9c9'; + } + + return '#fff'; +} + +module.exports = { + rootStyle: rootStyle, + loadingColor: loadingColor, +}; diff --git a/src/wxcomponents/vant-weapp/button/index.wxss b/src/wxcomponents/vant-weapp/button/index.wxss new file mode 100755 index 0000000..bd8bb5a --- /dev/null +++ b/src/wxcomponents/vant-weapp/button/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-button{-webkit-text-size-adjust:100%;align-items:center;-webkit-appearance:none;border-radius:var(--button-border-radius,2px);box-sizing:border-box;display:inline-flex;font-size:var(--button-default-font-size,16px);height:var(--button-default-height,44px);justify-content:center;line-height:var(--button-line-height,20px);padding:0;position:relative;text-align:center;transition:opacity .2s;vertical-align:middle}.van-button:before{background-color:#000;border:inherit;border-color:#000;border-radius:inherit;content:" ";height:100%;left:50%;opacity:0;position:absolute;top:50%;transform:translate(-50%,-50%);width:100%}.van-button:after{border-width:0}.van-button--active:before{opacity:.15}.van-button--unclickable:after{display:none}.van-button--default{background:var(--button-default-background-color,#fff);border:var(--button-border-width,1px) solid var(--button-default-border-color,#ebedf0);color:var(--button-default-color,#323233)}.van-button--primary{background:var(--button-primary-background-color,#07c160);border:var(--button-border-width,1px) solid var(--button-primary-border-color,#07c160);color:var(--button-primary-color,#fff)}.van-button--info{background:var(--button-info-background-color,#1989fa);border:var(--button-border-width,1px) solid var(--button-info-border-color,#1989fa);color:var(--button-info-color,#fff)}.van-button--danger{background:var(--button-danger-background-color,#ee0a24);border:var(--button-border-width,1px) solid var(--button-danger-border-color,#ee0a24);color:var(--button-danger-color,#fff)}.van-button--warning{background:var(--button-warning-background-color,#ff976a);border:var(--button-border-width,1px) solid var(--button-warning-border-color,#ff976a);color:var(--button-warning-color,#fff)}.van-button--plain{background:var(--button-plain-background-color,#fff)}.van-button--plain.van-button--primary{color:var(--button-primary-background-color,#07c160)}.van-button--plain.van-button--info{color:var(--button-info-background-color,#1989fa)}.van-button--plain.van-button--danger{color:var(--button-danger-background-color,#ee0a24)}.van-button--plain.van-button--warning{color:var(--button-warning-background-color,#ff976a)}.van-button--large{height:var(--button-large-height,50px);width:100%}.van-button--normal{font-size:var(--button-normal-font-size,14px);padding:0 15px}.van-button--small{font-size:var(--button-small-font-size,12px);height:var(--button-small-height,30px);min-width:var(--button-small-min-width,60px);padding:0 var(--padding-xs,8px)}.van-button--mini{display:inline-block;font-size:var(--button-mini-font-size,10px);height:var(--button-mini-height,22px);min-width:var(--button-mini-min-width,50px)}.van-button--mini+.van-button--mini{margin-left:5px}.van-button--block{display:flex;width:100%}.van-button--round{border-radius:var(--button-round-border-radius,999px)}.van-button--square{border-radius:0}.van-button--disabled{opacity:var(--button-disabled-opacity,.5)}.van-button__text{display:inline}.van-button__icon+.van-button__text:not(:empty),.van-button__loading-text{margin-left:4px}.van-button__icon{line-height:inherit!important;min-width:1em;vertical-align:top}.van-button--hairline{border-width:0;padding-top:1px}.van-button--hairline:after{border-color:inherit;border-radius:calc(var(--button-border-radius, 2px)*2);border-width:1px}.van-button--hairline.van-button--round:after{border-radius:var(--button-round-border-radius,999px)}.van-button--hairline.van-button--square:after{border-radius:0} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/calendar/calendar.wxml b/src/wxcomponents/vant-weapp/calendar/calendar.wxml new file mode 100755 index 0000000..2ba6f30 --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/calendar.wxml @@ -0,0 +1,68 @@ + +
+ +
+ + + + + + + + + + + + {{ + computed.getButtonDisabled(type, currentDate, minRange) + ? confirmDisabledText + : confirmText + }} + + +
diff --git a/src/wxcomponents/vant-weapp/calendar/components/header/index.d.ts b/src/wxcomponents/vant-weapp/calendar/components/header/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/components/header/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/calendar/components/header/index.js b/src/wxcomponents/vant-weapp/calendar/components/header/index.js new file mode 100755 index 0000000..8fb3682 --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/components/header/index.js @@ -0,0 +1,37 @@ +import { VantComponent } from '../../../common/component'; +VantComponent({ + props: { + title: { + type: String, + value: '日期选择', + }, + subtitle: String, + showTitle: Boolean, + showSubtitle: Boolean, + firstDayOfWeek: { + type: Number, + observer: 'initWeekDay', + }, + }, + data: { + weekdays: [], + }, + created() { + this.initWeekDay(); + }, + methods: { + initWeekDay() { + const defaultWeeks = ['日', '一', '二', '三', '四', '五', '六']; + const firstDayOfWeek = this.data.firstDayOfWeek || 0; + this.setData({ + weekdays: [ + ...defaultWeeks.slice(firstDayOfWeek, 7), + ...defaultWeeks.slice(0, firstDayOfWeek), + ], + }); + }, + onClickSubtitle(event) { + this.$emit('click-subtitle', event); + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/calendar/components/header/index.json b/src/wxcomponents/vant-weapp/calendar/components/header/index.json new file mode 100755 index 0000000..467ce29 --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/components/header/index.json @@ -0,0 +1,3 @@ +{ + "component": true +} diff --git a/src/wxcomponents/vant-weapp/calendar/components/header/index.wxml b/src/wxcomponents/vant-weapp/calendar/components/header/index.wxml new file mode 100755 index 0000000..7e56c83 --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/components/header/index.wxml @@ -0,0 +1,16 @@ + + + + {{ title }} + + + + {{ subtitle }} + + + + + {{ item }} + + + diff --git a/src/wxcomponents/vant-weapp/calendar/components/header/index.wxss b/src/wxcomponents/vant-weapp/calendar/components/header/index.wxss new file mode 100755 index 0000000..272537e --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/components/header/index.wxss @@ -0,0 +1 @@ +@import '../../../common/index.wxss';.van-calendar__header{box-shadow:var(--calendar-header-box-shadow,0 2px 10px hsla(220,1%,50%,.16));flex-shrink:0}.van-calendar__header-subtitle,.van-calendar__header-title{font-weight:var(--font-weight-bold,500);height:var(--calendar-header-title-height,44px);line-height:var(--calendar-header-title-height,44px);text-align:center}.van-calendar__header-title+.van-calendar__header-title,.van-calendar__header-title:empty{display:none}.van-calendar__header-title:empty+.van-calendar__header-title{display:block!important}.van-calendar__weekdays{display:flex}.van-calendar__weekday{flex:1;font-size:var(--calendar-weekdays-font-size,12px);line-height:var(--calendar-weekdays-height,30px);text-align:center} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/calendar/components/month/index.d.ts b/src/wxcomponents/vant-weapp/calendar/components/month/index.d.ts new file mode 100755 index 0000000..3ccf85a --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/components/month/index.d.ts @@ -0,0 +1,6 @@ +export interface Day { + date: Date; + type: string; + text: number; + bottomInfo?: string; +} diff --git a/src/wxcomponents/vant-weapp/calendar/components/month/index.js b/src/wxcomponents/vant-weapp/calendar/components/month/index.js new file mode 100755 index 0000000..d04c0fe --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/components/month/index.js @@ -0,0 +1,154 @@ +import { VantComponent } from '../../../common/component'; +import { getMonthEndDay, compareDay, getPrevDay, getNextDay, } from '../../utils'; +VantComponent({ + props: { + date: { + type: null, + observer: 'setDays', + }, + type: { + type: String, + observer: 'setDays', + }, + color: String, + minDate: { + type: null, + observer: 'setDays', + }, + maxDate: { + type: null, + observer: 'setDays', + }, + showMark: Boolean, + rowHeight: null, + formatter: { + type: null, + observer: 'setDays', + }, + currentDate: { + type: null, + observer: 'setDays', + }, + firstDayOfWeek: { + type: Number, + observer: 'setDays', + }, + allowSameDay: Boolean, + showSubtitle: Boolean, + showMonthTitle: Boolean, + }, + data: { + visible: true, + days: [], + }, + methods: { + onClick(event) { + const { index } = event.currentTarget.dataset; + const item = this.data.days[index]; + if (item.type !== 'disabled') { + this.$emit('click', item); + } + }, + setDays() { + const days = []; + const startDate = new Date(this.data.date); + const year = startDate.getFullYear(); + const month = startDate.getMonth(); + const totalDay = getMonthEndDay(startDate.getFullYear(), startDate.getMonth() + 1); + for (let day = 1; day <= totalDay; day++) { + const date = new Date(year, month, day); + const type = this.getDayType(date); + let config = { + date, + type, + text: day, + bottomInfo: this.getBottomInfo(type), + }; + if (this.data.formatter) { + config = this.data.formatter(config); + } + days.push(config); + } + this.setData({ days }); + }, + getMultipleDayType(day) { + const { currentDate } = this.data; + if (!Array.isArray(currentDate)) { + return ''; + } + const isSelected = (date) => currentDate.some((item) => compareDay(item, date) === 0); + if (isSelected(day)) { + const prevDay = getPrevDay(day); + const nextDay = getNextDay(day); + const prevSelected = isSelected(prevDay); + const nextSelected = isSelected(nextDay); + if (prevSelected && nextSelected) { + return 'multiple-middle'; + } + if (prevSelected) { + return 'end'; + } + return nextSelected ? 'start' : 'multiple-selected'; + } + return ''; + }, + getRangeDayType(day) { + const { currentDate, allowSameDay } = this.data; + if (!Array.isArray(currentDate)) { + return ''; + } + const [startDay, endDay] = currentDate; + if (!startDay) { + return ''; + } + const compareToStart = compareDay(day, startDay); + if (!endDay) { + return compareToStart === 0 ? 'start' : ''; + } + const compareToEnd = compareDay(day, endDay); + if (compareToStart === 0 && compareToEnd === 0 && allowSameDay) { + return 'start-end'; + } + if (compareToStart === 0) { + return 'start'; + } + if (compareToEnd === 0) { + return 'end'; + } + if (compareToStart > 0 && compareToEnd < 0) { + return 'middle'; + } + return ''; + }, + getDayType(day) { + const { type, minDate, maxDate, currentDate } = this.data; + if (compareDay(day, minDate) < 0 || compareDay(day, maxDate) > 0) { + return 'disabled'; + } + if (type === 'single') { + return compareDay(day, currentDate) === 0 ? 'selected' : ''; + } + if (type === 'multiple') { + return this.getMultipleDayType(day); + } + /* istanbul ignore else */ + if (type === 'range') { + return this.getRangeDayType(day); + } + return ''; + }, + getBottomInfo(type) { + if (this.data.type === 'range') { + if (type === 'start') { + return '开始'; + } + if (type === 'end') { + return '结束'; + } + if (type === 'start-end') { + return '开始/结束'; + } + } + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/calendar/components/month/index.json b/src/wxcomponents/vant-weapp/calendar/components/month/index.json new file mode 100755 index 0000000..467ce29 --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/components/month/index.json @@ -0,0 +1,3 @@ +{ + "component": true +} diff --git a/src/wxcomponents/vant-weapp/calendar/components/month/index.wxml b/src/wxcomponents/vant-weapp/calendar/components/month/index.wxml new file mode 100755 index 0000000..0c73b2f --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/components/month/index.wxml @@ -0,0 +1,39 @@ + + + + + + {{ computed.formatMonthTitle(date) }} + + + + + {{ computed.getMark(date) }} + + + + + {{ item.topInfo }} + {{ item.text }} + + {{ item.bottomInfo }} + + + + + {{ item.topInfo }} + {{ item.text }} + + {{ item.bottomInfo }} + + + + + diff --git a/src/wxcomponents/vant-weapp/calendar/components/month/index.wxs b/src/wxcomponents/vant-weapp/calendar/components/month/index.wxs new file mode 100755 index 0000000..55e45a5 --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/components/month/index.wxs @@ -0,0 +1,71 @@ +/* eslint-disable */ +var utils = require('../../utils.wxs'); + +function getMark(date) { + return getDate(date).getMonth() + 1; +} + +var ROW_HEIGHT = 64; + +function getDayStyle(type, index, date, rowHeight, color, firstDayOfWeek) { + var style = []; + var current = getDate(date).getDay() || 7; + var offset = current < firstDayOfWeek ? (7 - firstDayOfWeek + current) : + current === 7 && firstDayOfWeek === 0 ? 0 : + (current - firstDayOfWeek); + + if (index === 0) { + style.push(['margin-left', (100 * offset) / 7 + '%']); + } + + if (rowHeight !== ROW_HEIGHT) { + style.push(['height', rowHeight + 'px']); + } + + if (color) { + if ( + type === 'start' || + type === 'end' || + type === 'start-end' || + type === 'multiple-selected' || + type === 'multiple-middle' + ) { + style.push(['background', color]); + } else if (type === 'middle') { + style.push(['color', color]); + } + } + + return style + .map(function(item) { + return item.join(':'); + }) + .join(';'); +} + +function formatMonthTitle(date) { + date = getDate(date); + return date.getFullYear() + '年' + (date.getMonth() + 1) + '月'; +} + +function getMonthStyle(visible, date, rowHeight) { + if (!visible) { + date = getDate(date); + + var totalDay = utils.getMonthEndDay( + date.getFullYear(), + date.getMonth() + 1 + ); + var offset = getDate(date).getDay(); + var padding = Math.ceil((totalDay + offset) / 7) * rowHeight; + + return 'padding-bottom:' + padding + 'px'; + } +} + +module.exports = { + getMark: getMark, + getDayStyle: getDayStyle, + formatMonthTitle: formatMonthTitle, + getMonthStyle: getMonthStyle +}; diff --git a/src/wxcomponents/vant-weapp/calendar/components/month/index.wxss b/src/wxcomponents/vant-weapp/calendar/components/month/index.wxss new file mode 100755 index 0000000..9aee73d --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/components/month/index.wxss @@ -0,0 +1 @@ +@import '../../../common/index.wxss';.van-calendar{background-color:var(--calendar-background-color,#fff);display:flex;flex-direction:column;height:100%}.van-calendar__month-title{font-size:var(--calendar-month-title-font-size,14px);font-weight:var(--font-weight-bold,500);height:var(--calendar-header-title-height,44px);line-height:var(--calendar-header-title-height,44px);text-align:center}.van-calendar__days{display:flex;flex-wrap:wrap;position:relative;-webkit-user-select:none;user-select:none}.van-calendar__month-mark{color:var(--calendar-month-mark-color,rgba(242,243,245,.8));font-size:var(--calendar-month-mark-font-size,160px);left:50%;pointer-events:none;position:absolute;top:50%;transform:translate(-50%,-50%);z-index:0}.van-calendar__day,.van-calendar__selected-day{align-items:center;display:flex;justify-content:center;text-align:center}.van-calendar__day{font-size:var(--calendar-day-font-size,16px);height:var(--calendar-day-height,64px);position:relative;width:14.285%}.van-calendar__day--end,.van-calendar__day--multiple-middle,.van-calendar__day--multiple-selected,.van-calendar__day--start,.van-calendar__day--start-end{background-color:var(--calendar-range-edge-background-color,#ee0a24);color:var(--calendar-range-edge-color,#fff)}.van-calendar__day--start{border-radius:4px 0 0 4px}.van-calendar__day--end{border-radius:0 4px 4px 0}.van-calendar__day--multiple-selected,.van-calendar__day--start-end{border-radius:4px}.van-calendar__day--middle{color:var(--calendar-range-middle-color,#ee0a24)}.van-calendar__day--middle:after{background-color:currentColor;bottom:0;content:"";left:0;opacity:var(--calendar-range-middle-background-opacity,.1);position:absolute;right:0;top:0}.van-calendar__day--disabled{color:var(--calendar-day-disabled-color,#c8c9cc);cursor:default}.van-calendar__bottom-info,.van-calendar__top-info{font-size:var(--calendar-info-font-size,10px);left:0;line-height:var(--calendar-info-line-height,14px);position:absolute;right:0}@media (max-width:350px){.van-calendar__bottom-info,.van-calendar__top-info{font-size:9px}}.van-calendar__top-info{top:6px}.van-calendar__bottom-info{bottom:6px}.van-calendar__selected-day{background-color:var(--calendar-selected-day-background-color,#ee0a24);border-radius:4px;color:var(--calendar-selected-day-color,#fff);height:var(--calendar-selected-day-size,54px);width:var(--calendar-selected-day-size,54px)} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/calendar/index.d.ts b/src/wxcomponents/vant-weapp/calendar/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/calendar/index.js b/src/wxcomponents/vant-weapp/calendar/index.js new file mode 100755 index 0000000..bd3b883 --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/index.js @@ -0,0 +1,356 @@ +import { VantComponent } from '../common/component'; +import { ROW_HEIGHT, getPrevDay, getNextDay, getToday, compareDay, copyDates, calcDateNum, formatMonthTitle, compareMonth, getMonths, getDayByOffset, } from './utils'; +import Toast from '../toast/toast'; +import { requestAnimationFrame } from '../common/utils'; +const initialMinDate = getToday().getTime(); +const initialMaxDate = (() => { + const now = getToday(); + return new Date(now.getFullYear(), now.getMonth() + 6, now.getDate()).getTime(); +})(); +const getTime = (date) => date instanceof Date ? date.getTime() : date; +VantComponent({ + props: { + title: { + type: String, + value: '日期选择', + }, + color: String, + show: { + type: Boolean, + observer(val) { + if (val) { + this.initRect(); + this.scrollIntoView(); + } + }, + }, + formatter: null, + confirmText: { + type: String, + value: '确定', + }, + confirmDisabledText: { + type: String, + value: '确定', + }, + rangePrompt: String, + showRangePrompt: { + type: Boolean, + value: true, + }, + defaultDate: { + type: null, + value: getToday().getTime(), + observer(val) { + this.setData({ currentDate: val }); + this.scrollIntoView(); + }, + }, + allowSameDay: Boolean, + type: { + type: String, + value: 'single', + observer: 'reset', + }, + minDate: { + type: Number, + value: initialMinDate, + }, + maxDate: { + type: Number, + value: initialMaxDate, + }, + position: { + type: String, + value: 'bottom', + }, + rowHeight: { + type: null, + value: ROW_HEIGHT, + }, + round: { + type: Boolean, + value: true, + }, + poppable: { + type: Boolean, + value: true, + }, + showMark: { + type: Boolean, + value: true, + }, + showTitle: { + type: Boolean, + value: true, + }, + showConfirm: { + type: Boolean, + value: true, + }, + showSubtitle: { + type: Boolean, + value: true, + }, + safeAreaInsetBottom: { + type: Boolean, + value: true, + }, + closeOnClickOverlay: { + type: Boolean, + value: true, + }, + maxRange: { + type: null, + value: null, + }, + minRange: { + type: Number, + value: 1, + }, + firstDayOfWeek: { + type: Number, + value: 0, + }, + readonly: Boolean, + }, + data: { + subtitle: '', + currentDate: null, + scrollIntoView: '', + }, + watch: { + minDate() { + this.initRect(); + }, + maxDate() { + this.initRect(); + }, + }, + created() { + this.setData({ + currentDate: this.getInitialDate(this.data.defaultDate), + }); + }, + mounted() { + if (this.data.show || !this.data.poppable) { + this.initRect(); + this.scrollIntoView(); + } + }, + methods: { + reset() { + this.setData({ currentDate: this.getInitialDate(this.data.defaultDate) }); + this.scrollIntoView(); + }, + initRect() { + if (this.contentObserver != null) { + this.contentObserver.disconnect(); + } + const contentObserver = this.createIntersectionObserver({ + thresholds: [0, 0.1, 0.9, 1], + observeAll: true, + }); + this.contentObserver = contentObserver; + contentObserver.relativeTo('.van-calendar__body'); + contentObserver.observe('.month', (res) => { + if (res.boundingClientRect.top <= res.relativeRect.top) { + // @ts-ignore + this.setData({ subtitle: formatMonthTitle(res.dataset.date) }); + } + }); + }, + limitDateRange(date, minDate = null, maxDate = null) { + minDate = minDate || this.data.minDate; + maxDate = maxDate || this.data.maxDate; + if (compareDay(date, minDate) === -1) { + return minDate; + } + if (compareDay(date, maxDate) === 1) { + return maxDate; + } + return date; + }, + getInitialDate(defaultDate = null) { + const { type, minDate, maxDate, allowSameDay } = this.data; + if (!defaultDate) + return []; + const now = getToday().getTime(); + if (type === 'range') { + if (!Array.isArray(defaultDate)) { + defaultDate = []; + } + const [startDay, endDay] = defaultDate || []; + const startDate = getTime(startDay || now); + const start = this.limitDateRange(startDate, minDate, allowSameDay ? startDate : getPrevDay(new Date(maxDate)).getTime()); + const date = getTime(endDay || now); + const end = this.limitDateRange(date, allowSameDay ? date : getNextDay(new Date(minDate)).getTime()); + return [start, end]; + } + if (type === 'multiple') { + if (Array.isArray(defaultDate)) { + return defaultDate.map((date) => this.limitDateRange(date)); + } + return [this.limitDateRange(now)]; + } + if (!defaultDate || Array.isArray(defaultDate)) { + defaultDate = now; + } + return this.limitDateRange(defaultDate); + }, + scrollIntoView() { + requestAnimationFrame(() => { + const { currentDate, type, show, poppable, minDate, maxDate } = this.data; + if (!currentDate) + return; + // @ts-ignore + const targetDate = type === 'single' ? currentDate : currentDate[0]; + const displayed = show || !poppable; + if (!targetDate || !displayed) { + return; + } + const months = getMonths(minDate, maxDate); + months.some((month, index) => { + if (compareMonth(month, targetDate) === 0) { + this.setData({ scrollIntoView: `month${index}` }); + return true; + } + return false; + }); + }); + }, + onOpen() { + this.$emit('open'); + }, + onOpened() { + this.$emit('opened'); + }, + onClose() { + this.$emit('close'); + }, + onClosed() { + this.$emit('closed'); + }, + onClickDay(event) { + if (this.data.readonly) { + return; + } + let { date } = event.detail; + const { type, currentDate, allowSameDay } = this.data; + if (type === 'range') { + // @ts-ignore + const [startDay, endDay] = currentDate; + if (startDay && !endDay) { + const compareToStart = compareDay(date, startDay); + if (compareToStart === 1) { + const { days } = this.selectComponent('.month').data; + days.some((day, index) => { + const isDisabled = day.type === 'disabled' && + getTime(startDay) < getTime(day.date) && + getTime(day.date) < getTime(date); + if (isDisabled) { + ({ date } = days[index - 1]); + } + return isDisabled; + }); + this.select([startDay, date], true); + } + else if (compareToStart === -1) { + this.select([date, null]); + } + else if (allowSameDay) { + this.select([date, date], true); + } + } + else { + this.select([date, null]); + } + } + else if (type === 'multiple') { + let selectedIndex; + // @ts-ignore + const selected = currentDate.some((dateItem, index) => { + const equal = compareDay(dateItem, date) === 0; + if (equal) { + selectedIndex = index; + } + return equal; + }); + if (selected) { + // @ts-ignore + const cancelDate = currentDate.splice(selectedIndex, 1); + this.setData({ currentDate }); + this.unselect(cancelDate); + } + else { + // @ts-ignore + this.select([...currentDate, date]); + } + } + else { + this.select(date, true); + } + }, + unselect(dateArray) { + const date = dateArray[0]; + if (date) { + this.$emit('unselect', copyDates(date)); + } + }, + select(date, complete) { + if (complete && this.data.type === 'range') { + const valid = this.checkRange(date); + if (!valid) { + // auto selected to max range if showConfirm + if (this.data.showConfirm) { + this.emit([ + date[0], + getDayByOffset(date[0], this.data.maxRange - 1), + ]); + } + else { + this.emit(date); + } + return; + } + } + this.emit(date); + if (complete && !this.data.showConfirm) { + this.onConfirm(); + } + }, + emit(date) { + this.setData({ + currentDate: Array.isArray(date) ? date.map(getTime) : getTime(date), + }); + this.$emit('select', copyDates(date)); + }, + checkRange(date) { + const { maxRange, rangePrompt, showRangePrompt } = this.data; + if (maxRange && calcDateNum(date) > maxRange) { + if (showRangePrompt) { + Toast({ + context: this, + message: rangePrompt || `选择天数不能超过 ${maxRange} 天`, + }); + } + this.$emit('over-range'); + return false; + } + return true; + }, + onConfirm() { + if (this.data.type === 'range' && + !this.checkRange(this.data.currentDate)) { + return; + } + wx.nextTick(() => { + // @ts-ignore + this.$emit('confirm', copyDates(this.data.currentDate)); + }); + }, + onClickSubtitle(event) { + this.$emit('click-subtitle', event); + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/calendar/index.json b/src/wxcomponents/vant-weapp/calendar/index.json new file mode 100755 index 0000000..397d5ae --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/index.json @@ -0,0 +1,10 @@ +{ + "component": true, + "usingComponents": { + "header": "./components/header/index", + "month": "./components/month/index", + "van-button": "../button/index", + "van-popup": "../popup/index", + "van-toast": "../toast/index" + } +} diff --git a/src/wxcomponents/vant-weapp/calendar/index.wxml b/src/wxcomponents/vant-weapp/calendar/index.wxml new file mode 100755 index 0000000..9667eef --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/index.wxml @@ -0,0 +1,26 @@ + + + + + + + + + + + + diff --git a/src/wxcomponents/vant-weapp/calendar/index.wxs b/src/wxcomponents/vant-weapp/calendar/index.wxs new file mode 100755 index 0000000..0a56646 --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/index.wxs @@ -0,0 +1,37 @@ +/* eslint-disable */ +var utils = require('./utils.wxs'); + +function getMonths(minDate, maxDate) { + var months = []; + var cursor = getDate(minDate); + + cursor.setDate(1); + + do { + months.push(cursor.getTime()); + cursor.setMonth(cursor.getMonth() + 1); + } while (utils.compareMonth(cursor, getDate(maxDate)) !== 1); + + return months; +} + +function getButtonDisabled(type, currentDate, minRange) { + if (currentDate == null) { + return true; + } + + if (type === 'range') { + return !currentDate[0] || !currentDate[1]; + } + + if (type === 'multiple') { + return currentDate.length < minRange; + } + + return !currentDate; +} + +module.exports = { + getMonths: getMonths, + getButtonDisabled: getButtonDisabled +}; diff --git a/src/wxcomponents/vant-weapp/calendar/index.wxss b/src/wxcomponents/vant-weapp/calendar/index.wxss new file mode 100755 index 0000000..a1f1cf0 --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-calendar{background-color:var(--calendar-background-color,#fff);display:flex;flex-direction:column;height:var(--calendar-height,100%)}.van-calendar__close-icon{top:11px}.van-calendar__popup--bottom,.van-calendar__popup--top{height:var(--calendar-popup-height,90%)}.van-calendar__popup--left,.van-calendar__popup--right{height:100%}.van-calendar__body{-webkit-overflow-scrolling:touch;flex:1;overflow:auto}.van-calendar__footer{flex-shrink:0;padding:0 var(--padding-md,16px)}.van-calendar__footer--safe-area-inset-bottom{padding-bottom:env(safe-area-inset-bottom)}.van-calendar__footer+.van-calendar__footer,.van-calendar__footer:empty{display:none}.van-calendar__footer:empty+.van-calendar__footer{display:block!important}.van-calendar__confirm{height:var(--calendar-confirm-button-height,36px)!important;line-height:var(--calendar-confirm-button-line-height,34px)!important;margin:var(--calendar-confirm-button-margin,7px 0)!important} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/calendar/utils.d.ts b/src/wxcomponents/vant-weapp/calendar/utils.d.ts new file mode 100755 index 0000000..889e6e7 --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/utils.d.ts @@ -0,0 +1,12 @@ +export declare const ROW_HEIGHT = 64; +export declare function formatMonthTitle(date: Date): string; +export declare function compareMonth(date1: Date | number, date2: Date | number): 0 | 1 | -1; +export declare function compareDay(day1: Date | number, day2: Date | number): 0 | 1 | -1; +export declare function getDayByOffset(date: Date, offset: number): Date; +export declare function getPrevDay(date: Date): Date; +export declare function getNextDay(date: Date): Date; +export declare function getToday(): Date; +export declare function calcDateNum(date: [Date, Date]): number; +export declare function copyDates(dates: Date | Date[]): Date | Date[]; +export declare function getMonthEndDay(year: number, month: number): number; +export declare function getMonths(minDate: number, maxDate: number): number[]; diff --git a/src/wxcomponents/vant-weapp/calendar/utils.js b/src/wxcomponents/vant-weapp/calendar/utils.js new file mode 100755 index 0000000..83d6971 --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/utils.js @@ -0,0 +1,83 @@ +export const ROW_HEIGHT = 64; +export function formatMonthTitle(date) { + if (!(date instanceof Date)) { + date = new Date(date); + } + return `${date.getFullYear()}年${date.getMonth() + 1}月`; +} +export function compareMonth(date1, date2) { + if (!(date1 instanceof Date)) { + date1 = new Date(date1); + } + if (!(date2 instanceof Date)) { + date2 = new Date(date2); + } + const year1 = date1.getFullYear(); + const year2 = date2.getFullYear(); + const month1 = date1.getMonth(); + const month2 = date2.getMonth(); + if (year1 === year2) { + return month1 === month2 ? 0 : month1 > month2 ? 1 : -1; + } + return year1 > year2 ? 1 : -1; +} +export function compareDay(day1, day2) { + if (!(day1 instanceof Date)) { + day1 = new Date(day1); + } + if (!(day2 instanceof Date)) { + day2 = new Date(day2); + } + const compareMonthResult = compareMonth(day1, day2); + if (compareMonthResult === 0) { + const date1 = day1.getDate(); + const date2 = day2.getDate(); + return date1 === date2 ? 0 : date1 > date2 ? 1 : -1; + } + return compareMonthResult; +} +export function getDayByOffset(date, offset) { + date = new Date(date); + date.setDate(date.getDate() + offset); + return date; +} +export function getPrevDay(date) { + return getDayByOffset(date, -1); +} +export function getNextDay(date) { + return getDayByOffset(date, 1); +} +export function getToday() { + const today = new Date(); + today.setHours(0, 0, 0, 0); + return today; +} +export function calcDateNum(date) { + const day1 = new Date(date[0]).getTime(); + const day2 = new Date(date[1]).getTime(); + return (day2 - day1) / (1000 * 60 * 60 * 24) + 1; +} +export function copyDates(dates) { + if (Array.isArray(dates)) { + return dates.map((date) => { + if (date === null) { + return date; + } + return new Date(date); + }); + } + return new Date(dates); +} +export function getMonthEndDay(year, month) { + return 32 - new Date(year, month - 1, 32).getDate(); +} +export function getMonths(minDate, maxDate) { + const months = []; + const cursor = new Date(minDate); + cursor.setDate(1); + do { + months.push(cursor.getTime()); + cursor.setMonth(cursor.getMonth() + 1); + } while (compareMonth(cursor, maxDate) !== 1); + return months; +} diff --git a/src/wxcomponents/vant-weapp/calendar/utils.wxs b/src/wxcomponents/vant-weapp/calendar/utils.wxs new file mode 100755 index 0000000..e57f6b3 --- /dev/null +++ b/src/wxcomponents/vant-weapp/calendar/utils.wxs @@ -0,0 +1,25 @@ +/* eslint-disable */ +function getMonthEndDay(year, month) { + return 32 - getDate(year, month - 1, 32).getDate(); +} + +function compareMonth(date1, date2) { + date1 = getDate(date1); + date2 = getDate(date2); + + var year1 = date1.getFullYear(); + var year2 = date2.getFullYear(); + var month1 = date1.getMonth(); + var month2 = date2.getMonth(); + + if (year1 === year2) { + return month1 === month2 ? 0 : month1 > month2 ? 1 : -1; + } + + return year1 > year2 ? 1 : -1; +} + +module.exports = { + getMonthEndDay: getMonthEndDay, + compareMonth: compareMonth +}; diff --git a/src/wxcomponents/vant-weapp/card/index.d.ts b/src/wxcomponents/vant-weapp/card/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/card/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/card/index.js b/src/wxcomponents/vant-weapp/card/index.js new file mode 100755 index 0000000..5bbd212 --- /dev/null +++ b/src/wxcomponents/vant-weapp/card/index.js @@ -0,0 +1,49 @@ +import { link } from '../mixins/link'; +import { VantComponent } from '../common/component'; +VantComponent({ + classes: [ + 'num-class', + 'desc-class', + 'thumb-class', + 'title-class', + 'price-class', + 'origin-price-class', + ], + mixins: [link], + props: { + tag: String, + num: String, + desc: String, + thumb: String, + title: String, + price: { + type: String, + observer: 'updatePrice', + }, + centered: Boolean, + lazyLoad: Boolean, + thumbLink: String, + originPrice: String, + thumbMode: { + type: String, + value: 'aspectFit', + }, + currency: { + type: String, + value: '¥', + }, + }, + methods: { + updatePrice() { + const { price } = this.data; + const priceArr = price.toString().split('.'); + this.setData({ + integerStr: priceArr[0], + decimalStr: priceArr[1] ? `.${priceArr[1]}` : '', + }); + }, + onClickThumb() { + this.jumpLink('thumbLink'); + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/card/index.json b/src/wxcomponents/vant-weapp/card/index.json new file mode 100755 index 0000000..e917407 --- /dev/null +++ b/src/wxcomponents/vant-weapp/card/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "van-tag": "../tag/index" + } +} diff --git a/src/wxcomponents/vant-weapp/card/index.wxml b/src/wxcomponents/vant-weapp/card/index.wxml new file mode 100755 index 0000000..62173e4 --- /dev/null +++ b/src/wxcomponents/vant-weapp/card/index.wxml @@ -0,0 +1,56 @@ + + + + + + + + + {{ tag }} + + + + + + + {{ title }} + + + {{ desc }} + + + + + + + + + {{ currency }} + {{ integerStr }} + {{ decimalStr }} + + + {{ currency }} {{ originPrice }} + + x {{ num }} + + + + + + + + + + diff --git a/src/wxcomponents/vant-weapp/card/index.wxss b/src/wxcomponents/vant-weapp/card/index.wxss new file mode 100755 index 0000000..0f4d7c5 --- /dev/null +++ b/src/wxcomponents/vant-weapp/card/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-card{background-color:var(--card-background-color,#fafafa);box-sizing:border-box;color:var(--card-text-color,#323233);font-size:var(--card-font-size,12px);padding:var(--card-padding,8px 16px);position:relative}.van-card__header{display:flex}.van-card__header--center{align-items:center;justify-content:center}.van-card__thumb{flex:none;height:var(--card-thumb-size,88px);margin-right:var(--padding-xs,8px);position:relative;width:var(--card-thumb-size,88px)}.van-card__thumb:empty{display:none}.van-card__img{border-radius:8px;height:100%;width:100%}.van-card__content{display:flex;flex:1;flex-direction:column;justify-content:space-between;min-height:var(--card-thumb-size,88px);min-width:0;position:relative}.van-card__content--center{justify-content:center}.van-card__desc,.van-card__title{word-wrap:break-word}.van-card__title{font-weight:700;line-height:var(--card-title-line-height,16px)}.van-card__desc{color:var(--card-desc-color,#646566);line-height:var(--card-desc-line-height,20px)}.van-card__bottom{line-height:20px}.van-card__price{color:var(--card-price-color,#ee0a24);display:inline-block;font-size:var(--card-price-font-size,12px);font-weight:700}.van-card__price-integer{font-size:var(--card-price-integer-font-size,16px)}.van-card__price-decimal,.van-card__price-integer{font-family:var(--card-price-font-family,Avenir-Heavy,PingFang SC,Helvetica Neue,Arial,sans-serif)}.van-card__origin-price{color:var(--card-origin-price-color,#646566);display:inline-block;font-size:var(--card-origin-price-font-size,10px);margin-left:5px;text-decoration:line-through}.van-card__num{float:right}.van-card__tag{left:0;position:absolute!important;top:2px}.van-card__footer{flex:none;text-align:right;width:100%} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/cascader/index.d.ts b/src/wxcomponents/vant-weapp/cascader/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/cascader/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/cascader/index.js b/src/wxcomponents/vant-weapp/cascader/index.js new file mode 100755 index 0000000..058e929 --- /dev/null +++ b/src/wxcomponents/vant-weapp/cascader/index.js @@ -0,0 +1,208 @@ +import { VantComponent } from '../common/component'; +var FieldName; +(function (FieldName) { + FieldName["TEXT"] = "text"; + FieldName["VALUE"] = "value"; + FieldName["CHILDREN"] = "children"; +})(FieldName || (FieldName = {})); +const defaultFieldNames = { + text: FieldName.TEXT, + value: FieldName.VALUE, + children: FieldName.CHILDREN, +}; +VantComponent({ + props: { + title: String, + value: { + type: String, + }, + placeholder: { + type: String, + value: '请选择', + }, + activeColor: { + type: String, + value: '#1989fa', + }, + options: { + type: Array, + value: [], + }, + swipeable: { + type: Boolean, + value: false, + }, + closeable: { + type: Boolean, + value: true, + }, + showHeader: { + type: Boolean, + value: true, + }, + closeIcon: { + type: String, + value: 'cross', + }, + fieldNames: { + type: Object, + value: defaultFieldNames, + observer: 'updateFieldNames', + }, + }, + data: { + tabs: [], + activeTab: 0, + textKey: FieldName.TEXT, + valueKey: FieldName.VALUE, + childrenKey: FieldName.CHILDREN, + innerValue: '', + }, + watch: { + options() { + this.updateTabs(); + }, + value(newVal) { + this.updateValue(newVal); + }, + }, + created() { + this.updateTabs(); + }, + methods: { + updateValue(val) { + if (val !== undefined) { + const values = this.data.tabs.map((tab) => tab.selected && tab.selected[this.data.valueKey]); + if (values.indexOf(val) > -1) { + return; + } + } + this.innerValue = val; + this.updateTabs(); + }, + updateFieldNames() { + const { text = 'text', value = 'value', children = 'children', } = this.data.fieldNames || defaultFieldNames; + this.setData({ + textKey: text, + valueKey: value, + childrenKey: children, + }); + }, + getSelectedOptionsByValue(options, value) { + for (let i = 0; i < options.length; i++) { + const option = options[i]; + if (option[this.data.valueKey] === value) { + return [option]; + } + if (option[this.data.childrenKey]) { + const selectedOptions = this.getSelectedOptionsByValue(option[this.data.childrenKey], value); + if (selectedOptions) { + return [option, ...selectedOptions]; + } + } + } + }, + updateTabs() { + const { options } = this.data; + const { innerValue } = this; + if (!options.length) { + return; + } + if (innerValue !== undefined) { + const selectedOptions = this.getSelectedOptionsByValue(options, innerValue); + if (selectedOptions) { + let optionsCursor = options; + const tabs = selectedOptions.map((option) => { + const tab = { + options: optionsCursor, + selected: option, + }; + const next = optionsCursor.find((item) => item[this.data.valueKey] === option[this.data.valueKey]); + if (next) { + optionsCursor = next[this.data.childrenKey]; + } + return tab; + }); + if (optionsCursor) { + tabs.push({ + options: optionsCursor, + selected: null, + }); + } + this.setData({ + tabs, + }); + wx.nextTick(() => { + this.setData({ + activeTab: tabs.length - 1, + }); + }); + return; + } + } + this.setData({ + tabs: [ + { + options, + selected: null, + }, + ], + }); + }, + onClose() { + this.$emit('close'); + }, + onClickTab(e) { + const { index: tabIndex, title } = e.detail; + this.$emit('click-tab', { title, tabIndex }); + this.setData({ + activeTab: tabIndex, + }); + }, + // 选中 + onSelect(e) { + const { option, tabIndex } = e.currentTarget.dataset; + if (option && option.disabled) { + return; + } + const { valueKey, childrenKey } = this.data; + let { tabs } = this.data; + tabs[tabIndex].selected = option; + if (tabs.length > tabIndex + 1) { + tabs = tabs.slice(0, tabIndex + 1); + } + if (option[childrenKey]) { + const nextTab = { + options: option[childrenKey], + selected: null, + }; + if (tabs[tabIndex + 1]) { + tabs[tabIndex + 1] = nextTab; + } + else { + tabs.push(nextTab); + } + wx.nextTick(() => { + this.setData({ + activeTab: tabIndex + 1, + }); + }); + } + this.setData({ + tabs, + }); + const selectedOptions = tabs.map((tab) => tab.selected).filter(Boolean); + const value = option[valueKey]; + const params = { + value, + tabIndex, + selectedOptions, + }; + this.innerValue = value; + this.$emit('change', params); + if (!option[childrenKey]) { + this.$emit('finish', params); + } + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/cascader/index.json b/src/wxcomponents/vant-weapp/cascader/index.json new file mode 100755 index 0000000..d0f75eb --- /dev/null +++ b/src/wxcomponents/vant-weapp/cascader/index.json @@ -0,0 +1,8 @@ +{ + "component": true, + "usingComponents": { + "van-icon": "../icon/index", + "van-tab": "../tab/index", + "van-tabs": "../tabs/index" + } +} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/cascader/index.wxml b/src/wxcomponents/vant-weapp/cascader/index.wxml new file mode 100755 index 0000000..1794b82 --- /dev/null +++ b/src/wxcomponents/vant-weapp/cascader/index.wxml @@ -0,0 +1,53 @@ + + + + {{ title }} + + + + + + + + + + + {{ option[textKey] }} + + + + + + + diff --git a/src/wxcomponents/vant-weapp/cascader/index.wxs b/src/wxcomponents/vant-weapp/cascader/index.wxs new file mode 100755 index 0000000..b1aab58 --- /dev/null +++ b/src/wxcomponents/vant-weapp/cascader/index.wxs @@ -0,0 +1,24 @@ +var utils = require('../wxs/utils.wxs'); +var style = require('../wxs/style.wxs'); + +function isSelected(tab, valueKey, option) { + return tab.selected && tab.selected[valueKey] === option[valueKey] +} + +function optionClass(tab, valueKey, option) { + return utils.bem('cascader__option', { selected: isSelected(tab, valueKey, option), disabled: option.disabled }) +} + +function optionStyle(data) { + var color = data.option.color || (isSelected(data.tab, data.valueKey, data.option) ? data.activeColor : undefined); + return style({ + color + }); +} + + +module.exports = { + isSelected: isSelected, + optionClass: optionClass, + optionStyle: optionStyle, +}; \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/cascader/index.wxss b/src/wxcomponents/vant-weapp/cascader/index.wxss new file mode 100755 index 0000000..7062486 --- /dev/null +++ b/src/wxcomponents/vant-weapp/cascader/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-cascader__header{align-items:center;display:flex;height:48px;justify-content:space-between;padding:0 16px}.van-cascader__title{font-size:16px;font-weight:600;line-height:20px}.van-cascader__close-icon{color:#c8c9cc;font-size:22px;height:22px}.van-cascader__tabs-wrap{height:48px!important;padding:0 8px}.van-cascader__tab{color:#323233!important;flex:none!important;font-weight:600!important;padding:0 8px!important}.van-cascader__tab--unselected{color:#969799!important;font-weight:400!important}.van-cascader__option{align-items:center;cursor:pointer;display:flex;font-size:14px;justify-content:space-between;line-height:20px;padding:10px 16px}.van-cascader__option:active{background-color:#f2f3f5}.van-cascader__option--selected{color:#1989fa;font-weight:600}.van-cascader__option--disabled{color:#c8c9cc;cursor:not-allowed}.van-cascader__option--disabled:active{background-color:initial}.van-cascader__options{-webkit-overflow-scrolling:touch;box-sizing:border-box;height:384px;overflow-y:auto;padding-top:6px} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/cell-group/index.d.ts b/src/wxcomponents/vant-weapp/cell-group/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/cell-group/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/cell-group/index.js b/src/wxcomponents/vant-weapp/cell-group/index.js new file mode 100755 index 0000000..170760f --- /dev/null +++ b/src/wxcomponents/vant-weapp/cell-group/index.js @@ -0,0 +1,11 @@ +import { VantComponent } from '../common/component'; +VantComponent({ + props: { + title: String, + border: { + type: Boolean, + value: true, + }, + inset: Boolean, + }, +}); diff --git a/src/wxcomponents/vant-weapp/cell-group/index.json b/src/wxcomponents/vant-weapp/cell-group/index.json new file mode 100755 index 0000000..467ce29 --- /dev/null +++ b/src/wxcomponents/vant-weapp/cell-group/index.json @@ -0,0 +1,3 @@ +{ + "component": true +} diff --git a/src/wxcomponents/vant-weapp/cell-group/index.wxml b/src/wxcomponents/vant-weapp/cell-group/index.wxml new file mode 100755 index 0000000..311e064 --- /dev/null +++ b/src/wxcomponents/vant-weapp/cell-group/index.wxml @@ -0,0 +1,11 @@ + + + + {{ title }} + + + + diff --git a/src/wxcomponents/vant-weapp/cell-group/index.wxss b/src/wxcomponents/vant-weapp/cell-group/index.wxss new file mode 100755 index 0000000..08b252f --- /dev/null +++ b/src/wxcomponents/vant-weapp/cell-group/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-cell-group--inset{border-radius:var(--cell-group-inset-border-radius,8px);margin:var(--cell-group-inset-padding,0 16px);overflow:hidden}.van-cell-group__title{color:var(--cell-group-title-color,#969799);font-size:var(--cell-group-title-font-size,14px);line-height:var(--cell-group-title-line-height,16px);padding:var(--cell-group-title-padding,16px 16px 8px)}.van-cell-group__title--inset{padding:var(--cell-group-inset-title-padding,16px 16px 8px 32px)} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/cell/index.d.ts b/src/wxcomponents/vant-weapp/cell/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/cell/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/cell/index.js b/src/wxcomponents/vant-weapp/cell/index.js new file mode 100755 index 0000000..35548b9 --- /dev/null +++ b/src/wxcomponents/vant-weapp/cell/index.js @@ -0,0 +1,38 @@ +import { link } from '../mixins/link'; +import { VantComponent } from '../common/component'; +VantComponent({ + classes: [ + 'title-class', + 'label-class', + 'value-class', + 'right-icon-class', + 'hover-class', + ], + mixins: [link], + props: { + title: null, + value: null, + icon: String, + size: String, + label: String, + center: Boolean, + isLink: Boolean, + required: Boolean, + clickable: Boolean, + titleWidth: String, + customStyle: String, + arrowDirection: String, + useLabelSlot: Boolean, + border: { + type: Boolean, + value: true, + }, + titleStyle: String, + }, + methods: { + onClick(event) { + this.$emit('click', event.detail); + this.jumpLink(); + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/cell/index.json b/src/wxcomponents/vant-weapp/cell/index.json new file mode 100755 index 0000000..0a336c0 --- /dev/null +++ b/src/wxcomponents/vant-weapp/cell/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "van-icon": "../icon/index" + } +} diff --git a/src/wxcomponents/vant-weapp/cell/index.wxml b/src/wxcomponents/vant-weapp/cell/index.wxml new file mode 100755 index 0000000..8387c3c --- /dev/null +++ b/src/wxcomponents/vant-weapp/cell/index.wxml @@ -0,0 +1,47 @@ + + + + + + + + + + {{ title }} + + + + + {{ label }} + + + + + {{ value }} + + + + + + + + diff --git a/src/wxcomponents/vant-weapp/cell/index.wxs b/src/wxcomponents/vant-weapp/cell/index.wxs new file mode 100755 index 0000000..e3500c4 --- /dev/null +++ b/src/wxcomponents/vant-weapp/cell/index.wxs @@ -0,0 +1,17 @@ +/* eslint-disable */ +var style = require('../wxs/style.wxs'); +var addUnit = require('../wxs/add-unit.wxs'); + +function titleStyle(data) { + return style([ + { + 'max-width': addUnit(data.titleWidth), + 'min-width': addUnit(data.titleWidth), + }, + data.titleStyle, + ]); +} + +module.exports = { + titleStyle: titleStyle, +}; diff --git a/src/wxcomponents/vant-weapp/cell/index.wxss b/src/wxcomponents/vant-weapp/cell/index.wxss new file mode 100755 index 0000000..1802f8e --- /dev/null +++ b/src/wxcomponents/vant-weapp/cell/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-cell{background-color:var(--cell-background-color,#fff);box-sizing:border-box;color:var(--cell-text-color,#323233);display:flex;font-size:var(--cell-font-size,14px);line-height:var(--cell-line-height,24px);padding:var(--cell-vertical-padding,10px) var(--cell-horizontal-padding,16px);position:relative;width:100%}.van-cell:after{border-bottom:1px solid #ebedf0;bottom:0;box-sizing:border-box;content:" ";left:16px;pointer-events:none;position:absolute;right:16px;transform:scaleY(.5);transform-origin:center}.van-cell--borderless:after{display:none}.van-cell-group{background-color:var(--cell-background-color,#fff)}.van-cell__label{color:var(--cell-label-color,#969799);font-size:var(--cell-label-font-size,12px);line-height:var(--cell-label-line-height,18px);margin-top:var(--cell-label-margin-top,3px)}.van-cell__value{color:var(--cell-value-color,#969799);overflow:hidden;text-align:right;vertical-align:middle}.van-cell__title,.van-cell__value{flex:1}.van-cell__title:empty,.van-cell__value:empty{display:none}.van-cell__left-icon-wrap,.van-cell__right-icon-wrap{align-items:center;display:flex;font-size:var(--cell-icon-size,16px);height:var(--cell-line-height,24px)}.van-cell__left-icon-wrap{margin-right:var(--padding-base,4px)}.van-cell__right-icon-wrap{color:var(--cell-right-icon-color,#969799);margin-left:var(--padding-base,4px)}.van-cell__left-icon{vertical-align:middle}.van-cell__left-icon,.van-cell__right-icon{line-height:var(--cell-line-height,24px)}.van-cell--clickable.van-cell--hover{background-color:var(--cell-active-color,#f2f3f5)}.van-cell--required{overflow:visible}.van-cell--required:before{color:var(--cell-required-color,#ee0a24);content:"*";font-size:var(--cell-font-size,14px);left:var(--padding-xs,8px);position:absolute}.van-cell--center{align-items:center}.van-cell--large{padding-bottom:var(--cell-large-vertical-padding,12px);padding-top:var(--cell-large-vertical-padding,12px)}.van-cell--large .van-cell__title{font-size:var(--cell-large-title-font-size,16px)}.van-cell--large .van-cell__value{font-size:var(--cell-large-value-font-size,16px)}.van-cell--large .van-cell__label{font-size:var(--cell-large-label-font-size,14px)} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/checkbox-group/index.d.ts b/src/wxcomponents/vant-weapp/checkbox-group/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/checkbox-group/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/checkbox-group/index.js b/src/wxcomponents/vant-weapp/checkbox-group/index.js new file mode 100755 index 0000000..c47d97d --- /dev/null +++ b/src/wxcomponents/vant-weapp/checkbox-group/index.js @@ -0,0 +1,36 @@ +import { useChildren } from '../common/relation'; +import { VantComponent } from '../common/component'; +VantComponent({ + field: true, + relation: useChildren('checkbox', function (target) { + this.updateChild(target); + }), + props: { + max: Number, + value: { + type: Array, + observer: 'updateChildren', + }, + disabled: { + type: Boolean, + observer: 'updateChildren', + }, + direction: { + type: String, + value: 'vertical', + }, + }, + methods: { + updateChildren() { + this.children.forEach((child) => this.updateChild(child)); + }, + updateChild(child) { + const { value, disabled, direction } = this.data; + child.setData({ + value: value.indexOf(child.data.name) !== -1, + parentDisabled: disabled, + direction, + }); + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/checkbox-group/index.json b/src/wxcomponents/vant-weapp/checkbox-group/index.json new file mode 100755 index 0000000..467ce29 --- /dev/null +++ b/src/wxcomponents/vant-weapp/checkbox-group/index.json @@ -0,0 +1,3 @@ +{ + "component": true +} diff --git a/src/wxcomponents/vant-weapp/checkbox-group/index.wxml b/src/wxcomponents/vant-weapp/checkbox-group/index.wxml new file mode 100755 index 0000000..638bf9d --- /dev/null +++ b/src/wxcomponents/vant-weapp/checkbox-group/index.wxml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/wxcomponents/vant-weapp/checkbox-group/index.wxss b/src/wxcomponents/vant-weapp/checkbox-group/index.wxss new file mode 100755 index 0000000..c5666d7 --- /dev/null +++ b/src/wxcomponents/vant-weapp/checkbox-group/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-checkbox-group--horizontal{display:flex;flex-wrap:wrap} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/checkbox/index.d.ts b/src/wxcomponents/vant-weapp/checkbox/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/checkbox/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/checkbox/index.js b/src/wxcomponents/vant-weapp/checkbox/index.js new file mode 100755 index 0000000..e3b78ab --- /dev/null +++ b/src/wxcomponents/vant-weapp/checkbox/index.js @@ -0,0 +1,77 @@ +import { useParent } from '../common/relation'; +import { VantComponent } from '../common/component'; +function emit(target, value) { + target.$emit('input', value); + target.$emit('change', value); +} +VantComponent({ + field: true, + relation: useParent('checkbox-group'), + classes: ['icon-class', 'label-class'], + props: { + value: Boolean, + disabled: Boolean, + useIconSlot: Boolean, + checkedColor: String, + labelPosition: { + type: String, + value: 'right', + }, + labelDisabled: Boolean, + shape: { + type: String, + value: 'round', + }, + iconSize: { + type: null, + value: 20, + }, + }, + data: { + parentDisabled: false, + direction: 'vertical', + }, + methods: { + emitChange(value) { + if (this.parent) { + this.setParentValue(this.parent, value); + } + else { + emit(this, value); + } + }, + toggle() { + const { parentDisabled, disabled, value } = this.data; + if (!disabled && !parentDisabled) { + this.emitChange(!value); + } + }, + onClickLabel() { + const { labelDisabled, parentDisabled, disabled, value } = this.data; + if (!disabled && !labelDisabled && !parentDisabled) { + this.emitChange(!value); + } + }, + setParentValue(parent, value) { + const parentValue = parent.data.value.slice(); + const { name } = this.data; + const { max } = parent.data; + if (value) { + if (max && parentValue.length >= max) { + return; + } + if (parentValue.indexOf(name) === -1) { + parentValue.push(name); + emit(parent, parentValue); + } + } + else { + const index = parentValue.indexOf(name); + if (index !== -1) { + parentValue.splice(index, 1); + emit(parent, parentValue); + } + } + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/checkbox/index.json b/src/wxcomponents/vant-weapp/checkbox/index.json new file mode 100755 index 0000000..0a336c0 --- /dev/null +++ b/src/wxcomponents/vant-weapp/checkbox/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "van-icon": "../icon/index" + } +} diff --git a/src/wxcomponents/vant-weapp/checkbox/index.wxml b/src/wxcomponents/vant-weapp/checkbox/index.wxml new file mode 100755 index 0000000..39a7bb0 --- /dev/null +++ b/src/wxcomponents/vant-weapp/checkbox/index.wxml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + diff --git a/src/wxcomponents/vant-weapp/checkbox/index.wxs b/src/wxcomponents/vant-weapp/checkbox/index.wxs new file mode 100755 index 0000000..eb9c772 --- /dev/null +++ b/src/wxcomponents/vant-weapp/checkbox/index.wxs @@ -0,0 +1,20 @@ +/* eslint-disable */ +var style = require('../wxs/style.wxs'); +var addUnit = require('../wxs/add-unit.wxs'); + +function iconStyle(checkedColor, value, disabled, parentDisabled, iconSize) { + var styles = { + 'font-size': addUnit(iconSize), + }; + + if (checkedColor && value && !disabled && !parentDisabled) { + styles['border-color'] = checkedColor; + styles['background-color'] = checkedColor; + } + + return style(styles); +} + +module.exports = { + iconStyle: iconStyle, +}; diff --git a/src/wxcomponents/vant-weapp/checkbox/index.wxss b/src/wxcomponents/vant-weapp/checkbox/index.wxss new file mode 100755 index 0000000..da2272a --- /dev/null +++ b/src/wxcomponents/vant-weapp/checkbox/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-checkbox{align-items:center;display:flex;overflow:hidden;-webkit-user-select:none;user-select:none}.van-checkbox--horizontal{margin-right:12px}.van-checkbox__icon-wrap,.van-checkbox__label{line-height:var(--checkbox-size,20px)}.van-checkbox__icon-wrap{flex:none}.van-checkbox__icon{align-items:center;border:1px solid var(--checkbox-border-color,#c8c9cc);box-sizing:border-box;color:transparent;display:flex;font-size:var(--checkbox-size,20px);height:1em;justify-content:center;text-align:center;transition-duration:var(--checkbox-transition-duration,.2s);transition-property:color,border-color,background-color;width:1em}.van-checkbox__icon--round{border-radius:100%}.van-checkbox__icon--checked{background-color:var(--checkbox-checked-icon-color,#1989fa);border-color:var(--checkbox-checked-icon-color,#1989fa);color:#fff}.van-checkbox__icon--disabled{background-color:var(--checkbox-disabled-background-color,#ebedf0);border-color:var(--checkbox-disabled-icon-color,#c8c9cc)}.van-checkbox__icon--disabled.van-checkbox__icon--checked{color:var(--checkbox-disabled-icon-color,#c8c9cc)}.van-checkbox__label{word-wrap:break-word;color:var(--checkbox-label-color,#323233);padding-left:var(--checkbox-label-margin,10px)}.van-checkbox__label--left{float:left;margin:0 var(--checkbox-label-margin,10px) 0 0}.van-checkbox__label--disabled{color:var(--checkbox-disabled-label-color,#c8c9cc)}.van-checkbox__label:empty{margin:0} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/circle/canvas.d.ts b/src/wxcomponents/vant-weapp/circle/canvas.d.ts new file mode 100755 index 0000000..8a0b71e --- /dev/null +++ b/src/wxcomponents/vant-weapp/circle/canvas.d.ts @@ -0,0 +1,4 @@ +/// +type CanvasContext = WechatMiniprogram.CanvasContext; +export declare function adaptor(ctx: CanvasContext & Record): CanvasContext; +export {}; diff --git a/src/wxcomponents/vant-weapp/circle/canvas.js b/src/wxcomponents/vant-weapp/circle/canvas.js new file mode 100755 index 0000000..3ade4cd --- /dev/null +++ b/src/wxcomponents/vant-weapp/circle/canvas.js @@ -0,0 +1,43 @@ +export function adaptor(ctx) { + // @ts-ignore + return Object.assign(ctx, { + setStrokeStyle(val) { + ctx.strokeStyle = val; + }, + setLineWidth(val) { + ctx.lineWidth = val; + }, + setLineCap(val) { + ctx.lineCap = val; + }, + setFillStyle(val) { + ctx.fillStyle = val; + }, + setFontSize(val) { + ctx.font = String(val); + }, + setGlobalAlpha(val) { + ctx.globalAlpha = val; + }, + setLineJoin(val) { + ctx.lineJoin = val; + }, + setTextAlign(val) { + ctx.textAlign = val; + }, + setMiterLimit(val) { + ctx.miterLimit = val; + }, + setShadow(offsetX, offsetY, blur, color) { + ctx.shadowOffsetX = offsetX; + ctx.shadowOffsetY = offsetY; + ctx.shadowBlur = blur; + ctx.shadowColor = color; + }, + setTextBaseline(val) { + ctx.textBaseline = val; + }, + createCircularGradient() { }, + draw() { }, + }); +} diff --git a/src/wxcomponents/vant-weapp/circle/index.d.ts b/src/wxcomponents/vant-weapp/circle/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/circle/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/circle/index.js b/src/wxcomponents/vant-weapp/circle/index.js new file mode 100755 index 0000000..0b60888 --- /dev/null +++ b/src/wxcomponents/vant-weapp/circle/index.js @@ -0,0 +1,197 @@ +import { BLUE, WHITE } from '../common/color'; +import { VantComponent } from '../common/component'; +import { getSystemInfoSync } from '../common/utils'; +import { isObj } from '../common/validator'; +import { canIUseCanvas2d } from '../common/version'; +import { adaptor } from './canvas'; +function format(rate) { + return Math.min(Math.max(rate, 0), 100); +} +const PERIMETER = 2 * Math.PI; +const BEGIN_ANGLE = -Math.PI / 2; +const STEP = 1; +VantComponent({ + props: { + text: String, + lineCap: { + type: String, + value: 'round', + }, + value: { + type: Number, + value: 0, + observer: 'reRender', + }, + speed: { + type: Number, + value: 50, + }, + size: { + type: Number, + value: 100, + observer() { + this.drawCircle(this.currentValue); + }, + }, + fill: String, + layerColor: { + type: String, + value: WHITE, + }, + color: { + type: null, + value: BLUE, + observer() { + this.setHoverColor().then(() => { + this.drawCircle(this.currentValue); + }); + }, + }, + type: { + type: String, + value: '', + }, + strokeWidth: { + type: Number, + value: 4, + }, + clockwise: { + type: Boolean, + value: true, + }, + }, + data: { + hoverColor: BLUE, + }, + methods: { + getContext() { + const { type, size } = this.data; + if (type === '' || !canIUseCanvas2d()) { + const ctx = wx.createCanvasContext('van-circle', this); + return Promise.resolve(ctx); + } + const dpr = getSystemInfoSync().pixelRatio; + return new Promise((resolve) => { + wx.createSelectorQuery() + .in(this) + .select('#van-circle') + .node() + .exec((res) => { + const canvas = res[0].node; + const ctx = canvas.getContext(type); + if (!this.inited) { + this.inited = true; + canvas.width = size * dpr; + canvas.height = size * dpr; + ctx.scale(dpr, dpr); + } + resolve(adaptor(ctx)); + }); + }); + }, + setHoverColor() { + const { color, size } = this.data; + if (isObj(color)) { + return this.getContext().then((context) => { + if (!context) + return; + const LinearColor = context.createLinearGradient(size, 0, 0, 0); + Object.keys(color) + .sort((a, b) => parseFloat(a) - parseFloat(b)) + .map((key) => LinearColor.addColorStop(parseFloat(key) / 100, color[key])); + this.hoverColor = LinearColor; + }); + } + this.hoverColor = color; + return Promise.resolve(); + }, + presetCanvas(context, strokeStyle, beginAngle, endAngle, fill) { + const { strokeWidth, lineCap, clockwise, size } = this.data; + const position = size / 2; + const radius = position - strokeWidth / 2; + context.setStrokeStyle(strokeStyle); + context.setLineWidth(strokeWidth); + context.setLineCap(lineCap); + context.beginPath(); + context.arc(position, position, radius, beginAngle, endAngle, !clockwise); + context.stroke(); + if (fill) { + context.setFillStyle(fill); + context.fill(); + } + }, + renderLayerCircle(context) { + const { layerColor, fill } = this.data; + this.presetCanvas(context, layerColor, 0, PERIMETER, fill); + }, + renderHoverCircle(context, formatValue) { + const { clockwise } = this.data; + // 结束角度 + const progress = PERIMETER * (formatValue / 100); + const endAngle = clockwise + ? BEGIN_ANGLE + progress + : 3 * Math.PI - (BEGIN_ANGLE + progress); + this.presetCanvas(context, this.hoverColor, BEGIN_ANGLE, endAngle); + }, + drawCircle(currentValue) { + const { size } = this.data; + this.getContext().then((context) => { + if (!context) + return; + context.clearRect(0, 0, size, size); + this.renderLayerCircle(context); + const formatValue = format(currentValue); + if (formatValue !== 0) { + this.renderHoverCircle(context, formatValue); + } + context.draw(); + }); + }, + reRender() { + // tofector 动画暂时没有想到好的解决方案 + const { value, speed } = this.data; + if (speed <= 0 || speed > 1000) { + this.drawCircle(value); + return; + } + this.clearMockInterval(); + this.currentValue = this.currentValue || 0; + const run = () => { + this.interval = setTimeout(() => { + if (this.currentValue !== value) { + if (Math.abs(this.currentValue - value) < STEP) { + this.currentValue = value; + } + else if (this.currentValue < value) { + this.currentValue += STEP; + } + else { + this.currentValue -= STEP; + } + this.drawCircle(this.currentValue); + run(); + } + else { + this.clearMockInterval(); + } + }, 1000 / speed); + }; + run(); + }, + clearMockInterval() { + if (this.interval) { + clearTimeout(this.interval); + this.interval = null; + } + }, + }, + mounted() { + this.currentValue = this.data.value; + this.setHoverColor().then(() => { + this.drawCircle(this.currentValue); + }); + }, + destroyed() { + this.clearMockInterval(); + }, +}); diff --git a/src/wxcomponents/vant-weapp/circle/index.json b/src/wxcomponents/vant-weapp/circle/index.json new file mode 100755 index 0000000..467ce29 --- /dev/null +++ b/src/wxcomponents/vant-weapp/circle/index.json @@ -0,0 +1,3 @@ +{ + "component": true +} diff --git a/src/wxcomponents/vant-weapp/circle/index.wxml b/src/wxcomponents/vant-weapp/circle/index.wxml new file mode 100755 index 0000000..52bc59f --- /dev/null +++ b/src/wxcomponents/vant-weapp/circle/index.wxml @@ -0,0 +1,9 @@ + + + + + + + + {{ text }} + diff --git a/src/wxcomponents/vant-weapp/circle/index.wxss b/src/wxcomponents/vant-weapp/circle/index.wxss new file mode 100755 index 0000000..2200751 --- /dev/null +++ b/src/wxcomponents/vant-weapp/circle/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-circle{display:inline-block;position:relative;text-align:center}.van-circle__text{color:var(--circle-text-color,#323233);left:0;position:absolute;top:50%;transform:translateY(-50%);width:100%} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/col/index.d.ts b/src/wxcomponents/vant-weapp/col/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/col/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/col/index.js b/src/wxcomponents/vant-weapp/col/index.js new file mode 100755 index 0000000..02bb78d --- /dev/null +++ b/src/wxcomponents/vant-weapp/col/index.js @@ -0,0 +1,9 @@ +import { useParent } from '../common/relation'; +import { VantComponent } from '../common/component'; +VantComponent({ + relation: useParent('row'), + props: { + span: Number, + offset: Number, + }, +}); diff --git a/src/wxcomponents/vant-weapp/col/index.json b/src/wxcomponents/vant-weapp/col/index.json new file mode 100755 index 0000000..467ce29 --- /dev/null +++ b/src/wxcomponents/vant-weapp/col/index.json @@ -0,0 +1,3 @@ +{ + "component": true +} diff --git a/src/wxcomponents/vant-weapp/col/index.wxml b/src/wxcomponents/vant-weapp/col/index.wxml new file mode 100755 index 0000000..975348b --- /dev/null +++ b/src/wxcomponents/vant-weapp/col/index.wxml @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/wxcomponents/vant-weapp/col/index.wxs b/src/wxcomponents/vant-weapp/col/index.wxs new file mode 100755 index 0000000..507c1cb --- /dev/null +++ b/src/wxcomponents/vant-weapp/col/index.wxs @@ -0,0 +1,18 @@ +/* eslint-disable */ +var style = require('../wxs/style.wxs'); +var addUnit = require('../wxs/add-unit.wxs'); + +function rootStyle(data) { + if (!data.gutter) { + return ''; + } + + return style({ + 'padding-right': addUnit(data.gutter / 2), + 'padding-left': addUnit(data.gutter / 2), + }); +} + +module.exports = { + rootStyle: rootStyle, +}; diff --git a/src/wxcomponents/vant-weapp/col/index.wxss b/src/wxcomponents/vant-weapp/col/index.wxss new file mode 100755 index 0000000..2fa265e --- /dev/null +++ b/src/wxcomponents/vant-weapp/col/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-col{box-sizing:border-box;float:left}.van-col--1{width:4.16666667%}.van-col--offset-1{margin-left:4.16666667%}.van-col--2{width:8.33333333%}.van-col--offset-2{margin-left:8.33333333%}.van-col--3{width:12.5%}.van-col--offset-3{margin-left:12.5%}.van-col--4{width:16.66666667%}.van-col--offset-4{margin-left:16.66666667%}.van-col--5{width:20.83333333%}.van-col--offset-5{margin-left:20.83333333%}.van-col--6{width:25%}.van-col--offset-6{margin-left:25%}.van-col--7{width:29.16666667%}.van-col--offset-7{margin-left:29.16666667%}.van-col--8{width:33.33333333%}.van-col--offset-8{margin-left:33.33333333%}.van-col--9{width:37.5%}.van-col--offset-9{margin-left:37.5%}.van-col--10{width:41.66666667%}.van-col--offset-10{margin-left:41.66666667%}.van-col--11{width:45.83333333%}.van-col--offset-11{margin-left:45.83333333%}.van-col--12{width:50%}.van-col--offset-12{margin-left:50%}.van-col--13{width:54.16666667%}.van-col--offset-13{margin-left:54.16666667%}.van-col--14{width:58.33333333%}.van-col--offset-14{margin-left:58.33333333%}.van-col--15{width:62.5%}.van-col--offset-15{margin-left:62.5%}.van-col--16{width:66.66666667%}.van-col--offset-16{margin-left:66.66666667%}.van-col--17{width:70.83333333%}.van-col--offset-17{margin-left:70.83333333%}.van-col--18{width:75%}.van-col--offset-18{margin-left:75%}.van-col--19{width:79.16666667%}.van-col--offset-19{margin-left:79.16666667%}.van-col--20{width:83.33333333%}.van-col--offset-20{margin-left:83.33333333%}.van-col--21{width:87.5%}.van-col--offset-21{margin-left:87.5%}.van-col--22{width:91.66666667%}.van-col--offset-22{margin-left:91.66666667%}.van-col--23{width:95.83333333%}.van-col--offset-23{margin-left:95.83333333%}.van-col--24{width:100%}.van-col--offset-24{margin-left:100%} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/collapse-item/animate.d.ts b/src/wxcomponents/vant-weapp/collapse-item/animate.d.ts new file mode 100755 index 0000000..32157b6 --- /dev/null +++ b/src/wxcomponents/vant-weapp/collapse-item/animate.d.ts @@ -0,0 +1,2 @@ +/// +export declare function setContentAnimate(context: WechatMiniprogram.Component.TrivialInstance, expanded: boolean, mounted: boolean): void; diff --git a/src/wxcomponents/vant-weapp/collapse-item/animate.js b/src/wxcomponents/vant-weapp/collapse-item/animate.js new file mode 100755 index 0000000..f966ac5 --- /dev/null +++ b/src/wxcomponents/vant-weapp/collapse-item/animate.js @@ -0,0 +1,39 @@ +import { getRect } from '../common/utils'; +function useAnimation(context, expanded, mounted, height) { + const animation = wx.createAnimation({ + duration: 0, + timingFunction: 'ease-in-out', + }); + if (expanded) { + if (height === 0) { + animation.height('auto').top(1).step(); + } + else { + animation + .height(height) + .top(1) + .step({ + duration: mounted ? 300 : 1, + }) + .height('auto') + .step(); + } + context.setData({ + animation: animation.export(), + }); + return; + } + animation.height(height).top(0).step({ duration: 1 }).height(0).step({ + duration: 300, + }); + context.setData({ + animation: animation.export(), + }); +} +export function setContentAnimate(context, expanded, mounted) { + getRect(context, '.van-collapse-item__content') + .then((rect) => rect.height) + .then((height) => { + useAnimation(context, expanded, mounted, height); + }); +} diff --git a/src/wxcomponents/vant-weapp/collapse-item/index.d.ts b/src/wxcomponents/vant-weapp/collapse-item/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/collapse-item/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/collapse-item/index.js b/src/wxcomponents/vant-weapp/collapse-item/index.js new file mode 100755 index 0000000..5bac368 --- /dev/null +++ b/src/wxcomponents/vant-weapp/collapse-item/index.js @@ -0,0 +1,60 @@ +import { VantComponent } from '../common/component'; +import { useParent } from '../common/relation'; +import { setContentAnimate } from './animate'; +VantComponent({ + classes: ['title-class', 'content-class'], + relation: useParent('collapse'), + props: { + size: String, + name: null, + title: null, + value: null, + icon: String, + label: String, + disabled: Boolean, + clickable: Boolean, + border: { + type: Boolean, + value: true, + }, + isLink: { + type: Boolean, + value: true, + }, + }, + data: { + expanded: false, + }, + mounted() { + this.updateExpanded(); + this.mounted = true; + }, + methods: { + updateExpanded() { + if (!this.parent) { + return; + } + const { value, accordion } = this.parent.data; + const { children = [] } = this.parent; + const { name } = this.data; + const index = children.indexOf(this); + const currentName = name == null ? index : name; + const expanded = accordion + ? value === currentName + : (value || []).some((name) => name === currentName); + if (expanded !== this.data.expanded) { + setContentAnimate(this, expanded, this.mounted); + } + this.setData({ index, expanded }); + }, + onClick() { + if (this.data.disabled) { + return; + } + const { name, expanded } = this.data; + const index = this.parent.children.indexOf(this); + const currentName = name == null ? index : name; + this.parent.switch(currentName, !expanded); + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/collapse-item/index.json b/src/wxcomponents/vant-weapp/collapse-item/index.json new file mode 100755 index 0000000..0e5425c --- /dev/null +++ b/src/wxcomponents/vant-weapp/collapse-item/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "van-cell": "../cell/index" + } +} diff --git a/src/wxcomponents/vant-weapp/collapse-item/index.wxml b/src/wxcomponents/vant-weapp/collapse-item/index.wxml new file mode 100755 index 0000000..f11d0d4 --- /dev/null +++ b/src/wxcomponents/vant-weapp/collapse-item/index.wxml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + diff --git a/src/wxcomponents/vant-weapp/collapse-item/index.wxss b/src/wxcomponents/vant-weapp/collapse-item/index.wxss new file mode 100755 index 0000000..4a65b5a --- /dev/null +++ b/src/wxcomponents/vant-weapp/collapse-item/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-collapse-item__title .van-cell__right-icon{transform:rotate(90deg);transition:transform var(--collapse-item-transition-duration,.3s)}.van-collapse-item__title--expanded .van-cell__right-icon{transform:rotate(-90deg)}.van-collapse-item__title--disabled .van-cell,.van-collapse-item__title--disabled .van-cell__right-icon{color:var(--collapse-item-title-disabled-color,#c8c9cc)!important}.van-collapse-item__title--disabled .van-cell--hover{background-color:#fff!important}.van-collapse-item__wrapper{overflow:hidden}.van-collapse-item__content{background-color:var(--collapse-item-content-background-color,#fff);color:var(--collapse-item-content-text-color,#969799);font-size:var(--collapse-item-content-font-size,13px);line-height:var(--collapse-item-content-line-height,1.5);padding:var(--collapse-item-content-padding,15px)} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/collapse/index.d.ts b/src/wxcomponents/vant-weapp/collapse/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/collapse/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/collapse/index.js b/src/wxcomponents/vant-weapp/collapse/index.js new file mode 100755 index 0000000..3616087 --- /dev/null +++ b/src/wxcomponents/vant-weapp/collapse/index.js @@ -0,0 +1,46 @@ +import { VantComponent } from '../common/component'; +import { useChildren } from '../common/relation'; +VantComponent({ + relation: useChildren('collapse-item'), + props: { + value: { + type: null, + observer: 'updateExpanded', + }, + accordion: { + type: Boolean, + observer: 'updateExpanded', + }, + border: { + type: Boolean, + value: true, + }, + }, + methods: { + updateExpanded() { + this.children.forEach((child) => { + child.updateExpanded(); + }); + }, + switch(name, expanded) { + const { accordion, value } = this.data; + const changeItem = name; + if (!accordion) { + name = expanded + ? (value || []).concat(name) + : (value || []).filter((activeName) => activeName !== name); + } + else { + name = expanded ? name : ''; + } + if (expanded) { + this.$emit('open', changeItem); + } + else { + this.$emit('close', changeItem); + } + this.$emit('change', name); + this.$emit('input', name); + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/collapse/index.json b/src/wxcomponents/vant-weapp/collapse/index.json new file mode 100755 index 0000000..467ce29 --- /dev/null +++ b/src/wxcomponents/vant-weapp/collapse/index.json @@ -0,0 +1,3 @@ +{ + "component": true +} diff --git a/src/wxcomponents/vant-weapp/collapse/index.wxml b/src/wxcomponents/vant-weapp/collapse/index.wxml new file mode 100755 index 0000000..fd4e171 --- /dev/null +++ b/src/wxcomponents/vant-weapp/collapse/index.wxml @@ -0,0 +1,3 @@ + + + diff --git a/src/wxcomponents/vant-weapp/collapse/index.wxss b/src/wxcomponents/vant-weapp/collapse/index.wxss new file mode 100755 index 0000000..99694d6 --- /dev/null +++ b/src/wxcomponents/vant-weapp/collapse/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss'; \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/common/color.d.ts b/src/wxcomponents/vant-weapp/common/color.d.ts new file mode 100755 index 0000000..386f307 --- /dev/null +++ b/src/wxcomponents/vant-weapp/common/color.d.ts @@ -0,0 +1,7 @@ +export declare const RED = "#ee0a24"; +export declare const BLUE = "#1989fa"; +export declare const WHITE = "#fff"; +export declare const GREEN = "#07c160"; +export declare const ORANGE = "#ff976a"; +export declare const GRAY = "#323233"; +export declare const GRAY_DARK = "#969799"; diff --git a/src/wxcomponents/vant-weapp/common/color.js b/src/wxcomponents/vant-weapp/common/color.js new file mode 100755 index 0000000..6b285bd --- /dev/null +++ b/src/wxcomponents/vant-weapp/common/color.js @@ -0,0 +1,7 @@ +export const RED = '#ee0a24'; +export const BLUE = '#1989fa'; +export const WHITE = '#fff'; +export const GREEN = '#07c160'; +export const ORANGE = '#ff976a'; +export const GRAY = '#323233'; +export const GRAY_DARK = '#969799'; diff --git a/src/wxcomponents/vant-weapp/common/component.d.ts b/src/wxcomponents/vant-weapp/common/component.d.ts new file mode 100755 index 0000000..1d0fd27 --- /dev/null +++ b/src/wxcomponents/vant-weapp/common/component.d.ts @@ -0,0 +1,4 @@ +/// +import { VantComponentOptions } from 'definitions/index'; +declare function VantComponent(vantOptions: VantComponentOptions): void; +export { VantComponent }; diff --git a/src/wxcomponents/vant-weapp/common/component.js b/src/wxcomponents/vant-weapp/common/component.js new file mode 100755 index 0000000..938d96b --- /dev/null +++ b/src/wxcomponents/vant-weapp/common/component.js @@ -0,0 +1,46 @@ +import { basic } from '../mixins/basic'; +function mapKeys(source, target, map) { + Object.keys(map).forEach((key) => { + if (source[key]) { + target[map[key]] = source[key]; + } + }); +} +function VantComponent(vantOptions) { + const options = {}; + mapKeys(vantOptions, options, { + data: 'data', + props: 'properties', + watch: 'observers', + mixins: 'behaviors', + methods: 'methods', + beforeCreate: 'created', + created: 'attached', + mounted: 'ready', + destroyed: 'detached', + classes: 'externalClasses', + }); + // add default externalClasses + options.externalClasses = options.externalClasses || []; + options.externalClasses.push('custom-class'); + // add default behaviors + options.behaviors = options.behaviors || []; + options.behaviors.push(basic); + // add relations + const { relation } = vantOptions; + if (relation) { + options.relations = relation.relations; + options.behaviors.push(relation.mixin); + } + // map field to form-field behavior + if (vantOptions.field) { + options.behaviors.push('wx://form-field'); + } + // add default options + options.options = { + multipleSlots: true, + addGlobalClass: true, + }; + Component(options); +} +export { VantComponent }; diff --git a/src/wxcomponents/vant-weapp/common/index.wxss b/src/wxcomponents/vant-weapp/common/index.wxss new file mode 100755 index 0000000..a73bb7a --- /dev/null +++ b/src/wxcomponents/vant-weapp/common/index.wxss @@ -0,0 +1 @@ +.van-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.van-multi-ellipsis--l2{-webkit-line-clamp:2}.van-multi-ellipsis--l2,.van-multi-ellipsis--l3{-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden;text-overflow:ellipsis}.van-multi-ellipsis--l3{-webkit-line-clamp:3}.van-clearfix:after{clear:both;content:"";display:table}.van-hairline,.van-hairline--bottom,.van-hairline--left,.van-hairline--right,.van-hairline--surround,.van-hairline--top,.van-hairline--top-bottom{position:relative}.van-hairline--bottom:after,.van-hairline--left:after,.van-hairline--right:after,.van-hairline--surround:after,.van-hairline--top-bottom:after,.van-hairline--top:after,.van-hairline:after{border:0 solid #ebedf0;bottom:-50%;box-sizing:border-box;content:" ";left:-50%;pointer-events:none;position:absolute;right:-50%;top:-50%;transform:scale(.5);transform-origin:center}.van-hairline--top:after{border-top-width:1px}.van-hairline--left:after{border-left-width:1px}.van-hairline--right:after{border-right-width:1px}.van-hairline--bottom:after{border-bottom-width:1px}.van-hairline--top-bottom:after{border-width:1px 0}.van-hairline--surround:after{border-width:1px} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/common/relation.d.ts b/src/wxcomponents/vant-weapp/common/relation.d.ts new file mode 100755 index 0000000..10193fa --- /dev/null +++ b/src/wxcomponents/vant-weapp/common/relation.d.ts @@ -0,0 +1,15 @@ +/// +type TrivialInstance = WechatMiniprogram.Component.TrivialInstance; +export declare function useParent(name: string, onEffect?: (this: TrivialInstance) => void): { + relations: { + [x: string]: WechatMiniprogram.Component.RelationOption; + }; + mixin: string; +}; +export declare function useChildren(name: string, onEffect?: (this: TrivialInstance, target: TrivialInstance) => void): { + relations: { + [x: string]: WechatMiniprogram.Component.RelationOption; + }; + mixin: string; +}; +export {}; diff --git a/src/wxcomponents/vant-weapp/common/relation.js b/src/wxcomponents/vant-weapp/common/relation.js new file mode 100755 index 0000000..04e2934 --- /dev/null +++ b/src/wxcomponents/vant-weapp/common/relation.js @@ -0,0 +1,56 @@ +export function useParent(name, onEffect) { + const path = `../${name}/index`; + return { + relations: { + [path]: { + type: 'ancestor', + linked() { + onEffect && onEffect.call(this); + }, + linkChanged() { + onEffect && onEffect.call(this); + }, + unlinked() { + onEffect && onEffect.call(this); + }, + }, + }, + mixin: Behavior({ + created() { + Object.defineProperty(this, 'parent', { + get: () => this.getRelationNodes(path)[0], + }); + Object.defineProperty(this, 'index', { + // @ts-ignore + get: () => { var _a, _b; return (_b = (_a = this.parent) === null || _a === void 0 ? void 0 : _a.children) === null || _b === void 0 ? void 0 : _b.indexOf(this); }, + }); + }, + }), + }; +} +export function useChildren(name, onEffect) { + const path = `../${name}/index`; + return { + relations: { + [path]: { + type: 'descendant', + linked(target) { + onEffect && onEffect.call(this, target); + }, + linkChanged(target) { + onEffect && onEffect.call(this, target); + }, + unlinked(target) { + onEffect && onEffect.call(this, target); + }, + }, + }, + mixin: Behavior({ + created() { + Object.defineProperty(this, 'children', { + get: () => this.getRelationNodes(path) || [], + }); + }, + }), + }; +} diff --git a/src/wxcomponents/vant-weapp/common/style/clearfix.wxss b/src/wxcomponents/vant-weapp/common/style/clearfix.wxss new file mode 100755 index 0000000..442246f --- /dev/null +++ b/src/wxcomponents/vant-weapp/common/style/clearfix.wxss @@ -0,0 +1 @@ +.van-clearfix:after{clear:both;content:"";display:table} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/common/style/ellipsis.wxss b/src/wxcomponents/vant-weapp/common/style/ellipsis.wxss new file mode 100755 index 0000000..ee701df --- /dev/null +++ b/src/wxcomponents/vant-weapp/common/style/ellipsis.wxss @@ -0,0 +1 @@ +.van-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.van-multi-ellipsis--l2{-webkit-line-clamp:2}.van-multi-ellipsis--l2,.van-multi-ellipsis--l3{-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden;text-overflow:ellipsis}.van-multi-ellipsis--l3{-webkit-line-clamp:3} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/common/style/hairline.wxss b/src/wxcomponents/vant-weapp/common/style/hairline.wxss new file mode 100755 index 0000000..f7c6260 --- /dev/null +++ b/src/wxcomponents/vant-weapp/common/style/hairline.wxss @@ -0,0 +1 @@ +.van-hairline,.van-hairline--bottom,.van-hairline--left,.van-hairline--right,.van-hairline--surround,.van-hairline--top,.van-hairline--top-bottom{position:relative}.van-hairline--bottom:after,.van-hairline--left:after,.van-hairline--right:after,.van-hairline--surround:after,.van-hairline--top-bottom:after,.van-hairline--top:after,.van-hairline:after{border:0 solid #ebedf0;bottom:-50%;box-sizing:border-box;content:" ";left:-50%;pointer-events:none;position:absolute;right:-50%;top:-50%;transform:scale(.5);transform-origin:center}.van-hairline--top:after{border-top-width:1px}.van-hairline--left:after{border-left-width:1px}.van-hairline--right:after{border-right-width:1px}.van-hairline--bottom:after{border-bottom-width:1px}.van-hairline--top-bottom:after{border-width:1px 0}.van-hairline--surround:after{border-width:1px} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/common/style/mixins/clearfix.wxss b/src/wxcomponents/vant-weapp/common/style/mixins/clearfix.wxss new file mode 100755 index 0000000..e69de29 diff --git a/src/wxcomponents/vant-weapp/common/style/mixins/ellipsis.wxss b/src/wxcomponents/vant-weapp/common/style/mixins/ellipsis.wxss new file mode 100755 index 0000000..e69de29 diff --git a/src/wxcomponents/vant-weapp/common/style/mixins/hairline.wxss b/src/wxcomponents/vant-weapp/common/style/mixins/hairline.wxss new file mode 100755 index 0000000..e69de29 diff --git a/src/wxcomponents/vant-weapp/common/style/var.wxss b/src/wxcomponents/vant-weapp/common/style/var.wxss new file mode 100755 index 0000000..e69de29 diff --git a/src/wxcomponents/vant-weapp/common/utils.d.ts b/src/wxcomponents/vant-weapp/common/utils.d.ts new file mode 100755 index 0000000..805b399 --- /dev/null +++ b/src/wxcomponents/vant-weapp/common/utils.d.ts @@ -0,0 +1,20 @@ +/// +/// +/// +/// +/// +export { isDef } from './validator'; +export { getSystemInfoSync } from './version'; +export declare function range(num: number, min: number, max: number): number; +export declare function nextTick(cb: (...args: any[]) => void): void; +export declare function addUnit(value?: string | number): string | undefined; +export declare function requestAnimationFrame(cb: () => void): NodeJS.Timeout; +export declare function pickExclude(obj: unknown, keys: string[]): {}; +export declare function getRect(context: WechatMiniprogram.Component.TrivialInstance, selector: string): Promise; +export declare function getAllRect(context: WechatMiniprogram.Component.TrivialInstance, selector: string): Promise; +export declare function groupSetData(context: WechatMiniprogram.Component.TrivialInstance, cb: () => void): void; +export declare function toPromise(promiseLike: Promise | unknown): Promise; +export declare function addNumber(num1: any, num2: any): number; +export declare const clamp: (num: any, min: any, max: any) => number; +export declare function getCurrentPage(): T & WechatMiniprogram.OptionalInterface & WechatMiniprogram.Page.InstanceProperties & WechatMiniprogram.Page.InstanceMethods & WechatMiniprogram.Page.Data & WechatMiniprogram.IAnyObject; +export declare const isPC: boolean; diff --git a/src/wxcomponents/vant-weapp/common/utils.js b/src/wxcomponents/vant-weapp/common/utils.js new file mode 100755 index 0000000..88cc17b --- /dev/null +++ b/src/wxcomponents/vant-weapp/common/utils.js @@ -0,0 +1,84 @@ +import { isDef, isNumber, isPlainObject, isPromise } from './validator'; +import { canIUseGroupSetData, canIUseNextTick, getSystemInfoSync, } from './version'; +export { isDef } from './validator'; +export { getSystemInfoSync } from './version'; +export function range(num, min, max) { + return Math.min(Math.max(num, min), max); +} +export function nextTick(cb) { + if (canIUseNextTick()) { + wx.nextTick(cb); + } + else { + setTimeout(() => { + cb(); + }, 1000 / 30); + } +} +export function addUnit(value) { + if (!isDef(value)) { + return undefined; + } + value = String(value); + return isNumber(value) ? `${value}px` : value; +} +export function requestAnimationFrame(cb) { + return setTimeout(() => { + cb(); + }, 1000 / 30); +} +export function pickExclude(obj, keys) { + if (!isPlainObject(obj)) { + return {}; + } + return Object.keys(obj).reduce((prev, key) => { + if (!keys.includes(key)) { + prev[key] = obj[key]; + } + return prev; + }, {}); +} +export function getRect(context, selector) { + return new Promise((resolve) => { + wx.createSelectorQuery() + .in(context) + .select(selector) + .boundingClientRect() + .exec((rect = []) => resolve(rect[0])); + }); +} +export function getAllRect(context, selector) { + return new Promise((resolve) => { + wx.createSelectorQuery() + .in(context) + .selectAll(selector) + .boundingClientRect() + .exec((rect = []) => resolve(rect[0])); + }); +} +export function groupSetData(context, cb) { + if (canIUseGroupSetData()) { + context.groupSetData(cb); + } + else { + cb(); + } +} +export function toPromise(promiseLike) { + if (isPromise(promiseLike)) { + return promiseLike; + } + return Promise.resolve(promiseLike); +} +// 浮点数精度处理 +export function addNumber(num1, num2) { + const cardinal = Math.pow(10, 10); + return Math.round((num1 + num2) * cardinal) / cardinal; +} +// 限制value在[min, max]之间 +export const clamp = (num, min, max) => Math.min(Math.max(num, min), max); +export function getCurrentPage() { + const pages = getCurrentPages(); + return pages[pages.length - 1]; +} +export const isPC = ['mac', 'windows'].includes(getSystemInfoSync().platform); diff --git a/src/wxcomponents/vant-weapp/common/validator.d.ts b/src/wxcomponents/vant-weapp/common/validator.d.ts new file mode 100755 index 0000000..152894a --- /dev/null +++ b/src/wxcomponents/vant-weapp/common/validator.d.ts @@ -0,0 +1,9 @@ +export declare function isFunction(val: unknown): val is Function; +export declare function isPlainObject(val: unknown): val is Record; +export declare function isPromise(val: unknown): val is Promise; +export declare function isDef(value: unknown): boolean; +export declare function isObj(x: unknown): x is Record; +export declare function isNumber(value: string): boolean; +export declare function isBoolean(value: unknown): value is boolean; +export declare function isImageUrl(url: string): boolean; +export declare function isVideoUrl(url: string): boolean; diff --git a/src/wxcomponents/vant-weapp/common/validator.js b/src/wxcomponents/vant-weapp/common/validator.js new file mode 100755 index 0000000..f11f844 --- /dev/null +++ b/src/wxcomponents/vant-weapp/common/validator.js @@ -0,0 +1,31 @@ +// eslint-disable-next-line @typescript-eslint/ban-types +export function isFunction(val) { + return typeof val === 'function'; +} +export function isPlainObject(val) { + return val !== null && typeof val === 'object' && !Array.isArray(val); +} +export function isPromise(val) { + return isPlainObject(val) && isFunction(val.then) && isFunction(val.catch); +} +export function isDef(value) { + return value !== undefined && value !== null; +} +export function isObj(x) { + const type = typeof x; + return x !== null && (type === 'object' || type === 'function'); +} +export function isNumber(value) { + return /^\d+(\.\d+)?$/.test(value); +} +export function isBoolean(value) { + return typeof value === 'boolean'; +} +const IMAGE_REGEXP = /\.(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg)/i; +const VIDEO_REGEXP = /\.(mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv)/i; +export function isImageUrl(url) { + return IMAGE_REGEXP.test(url); +} +export function isVideoUrl(url) { + return VIDEO_REGEXP.test(url); +} diff --git a/src/wxcomponents/vant-weapp/common/version.d.ts b/src/wxcomponents/vant-weapp/common/version.d.ts new file mode 100755 index 0000000..7142201 --- /dev/null +++ b/src/wxcomponents/vant-weapp/common/version.d.ts @@ -0,0 +1,9 @@ +/// +export declare function getSystemInfoSync(): WechatMiniprogram.SystemInfo; +export declare function canIUseModel(): boolean; +export declare function canIUseFormFieldButton(): boolean; +export declare function canIUseAnimate(): boolean; +export declare function canIUseGroupSetData(): boolean; +export declare function canIUseNextTick(): boolean; +export declare function canIUseCanvas2d(): boolean; +export declare function canIUseGetUserProfile(): boolean; diff --git a/src/wxcomponents/vant-weapp/common/version.js b/src/wxcomponents/vant-weapp/common/version.js new file mode 100755 index 0000000..c675e1f --- /dev/null +++ b/src/wxcomponents/vant-weapp/common/version.js @@ -0,0 +1,59 @@ +let systemInfo; +export function getSystemInfoSync() { + if (systemInfo == null) { + systemInfo = wx.getSystemInfoSync(); + } + return systemInfo; +} +function compareVersion(v1, v2) { + v1 = v1.split('.'); + v2 = v2.split('.'); + const len = Math.max(v1.length, v2.length); + while (v1.length < len) { + v1.push('0'); + } + while (v2.length < len) { + v2.push('0'); + } + for (let i = 0; i < len; i++) { + const num1 = parseInt(v1[i], 10); + const num2 = parseInt(v2[i], 10); + if (num1 > num2) { + return 1; + } + if (num1 < num2) { + return -1; + } + } + return 0; +} +function gte(version) { + const system = getSystemInfoSync(); + return compareVersion(system.SDKVersion, version) >= 0; +} +export function canIUseModel() { + return gte('2.9.3'); +} +export function canIUseFormFieldButton() { + return gte('2.10.3'); +} +export function canIUseAnimate() { + return gte('2.9.0'); +} +export function canIUseGroupSetData() { + return gte('2.4.0'); +} +export function canIUseNextTick() { + try { + return wx.canIUse('nextTick'); + } + catch (e) { + return gte('2.7.1'); + } +} +export function canIUseCanvas2d() { + return gte('2.9.0'); +} +export function canIUseGetUserProfile() { + return !!wx.getUserProfile; +} diff --git a/src/wxcomponents/vant-weapp/config-provider/index.d.ts b/src/wxcomponents/vant-weapp/config-provider/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/config-provider/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/config-provider/index.js b/src/wxcomponents/vant-weapp/config-provider/index.js new file mode 100755 index 0000000..0cb23f4 --- /dev/null +++ b/src/wxcomponents/vant-weapp/config-provider/index.js @@ -0,0 +1,9 @@ +import { VantComponent } from '../common/component'; +VantComponent({ + props: { + themeVars: { + type: Object, + value: {}, + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/config-provider/index.json b/src/wxcomponents/vant-weapp/config-provider/index.json new file mode 100755 index 0000000..467ce29 --- /dev/null +++ b/src/wxcomponents/vant-weapp/config-provider/index.json @@ -0,0 +1,3 @@ +{ + "component": true +} diff --git a/src/wxcomponents/vant-weapp/config-provider/index.wxml b/src/wxcomponents/vant-weapp/config-provider/index.wxml new file mode 100755 index 0000000..3cfb461 --- /dev/null +++ b/src/wxcomponents/vant-weapp/config-provider/index.wxml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/wxcomponents/vant-weapp/config-provider/index.wxs b/src/wxcomponents/vant-weapp/config-provider/index.wxs new file mode 100755 index 0000000..7ca0203 --- /dev/null +++ b/src/wxcomponents/vant-weapp/config-provider/index.wxs @@ -0,0 +1,29 @@ +/* eslint-disable */ +var object = require('../wxs/object.wxs'); +var style = require('../wxs/style.wxs'); + +function kebabCase(word) { + var newWord = word + .replace(getRegExp("[A-Z]", 'g'), function (i) { + return '-' + i; + }) + .toLowerCase() + .replace(getRegExp("^-"), ''); + + return newWord; +} + +function mapThemeVarsToCSSVars(themeVars) { + var cssVars = {}; + object.keys(themeVars).forEach(function (key) { + var cssVarsKey = '--' + kebabCase(key); + cssVars[cssVarsKey] = themeVars[key]; + }); + + return style(cssVars); +} + +module.exports = { + kebabCase: kebabCase, + mapThemeVarsToCSSVars: mapThemeVarsToCSSVars, +}; diff --git a/src/wxcomponents/vant-weapp/count-down/index.d.ts b/src/wxcomponents/vant-weapp/count-down/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/count-down/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/count-down/index.js b/src/wxcomponents/vant-weapp/count-down/index.js new file mode 100755 index 0000000..da24145 --- /dev/null +++ b/src/wxcomponents/vant-weapp/count-down/index.js @@ -0,0 +1,100 @@ +import { VantComponent } from '../common/component'; +import { isSameSecond, parseFormat, parseTimeData } from './utils'; +function simpleTick(fn) { + return setTimeout(fn, 30); +} +VantComponent({ + props: { + useSlot: Boolean, + millisecond: Boolean, + time: { + type: Number, + observer: 'reset', + }, + format: { + type: String, + value: 'HH:mm:ss', + }, + autoStart: { + type: Boolean, + value: true, + }, + }, + data: { + timeData: parseTimeData(0), + formattedTime: '0', + }, + destroyed() { + clearTimeout(this.tid); + this.tid = null; + }, + methods: { + // 开始 + start() { + if (this.counting) { + return; + } + this.counting = true; + this.endTime = Date.now() + this.remain; + this.tick(); + }, + // 暂停 + pause() { + this.counting = false; + clearTimeout(this.tid); + }, + // 重置 + reset() { + this.pause(); + this.remain = this.data.time; + this.setRemain(this.remain); + if (this.data.autoStart) { + this.start(); + } + }, + tick() { + if (this.data.millisecond) { + this.microTick(); + } + else { + this.macroTick(); + } + }, + microTick() { + this.tid = simpleTick(() => { + this.setRemain(this.getRemain()); + if (this.remain !== 0) { + this.microTick(); + } + }); + }, + macroTick() { + this.tid = simpleTick(() => { + const remain = this.getRemain(); + if (!isSameSecond(remain, this.remain) || remain === 0) { + this.setRemain(remain); + } + if (this.remain !== 0) { + this.macroTick(); + } + }); + }, + getRemain() { + return Math.max(this.endTime - Date.now(), 0); + }, + setRemain(remain) { + this.remain = remain; + const timeData = parseTimeData(remain); + if (this.data.useSlot) { + this.$emit('change', timeData); + } + this.setData({ + formattedTime: parseFormat(this.data.format, timeData), + }); + if (remain === 0) { + this.pause(); + this.$emit('finish'); + } + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/count-down/index.json b/src/wxcomponents/vant-weapp/count-down/index.json new file mode 100755 index 0000000..467ce29 --- /dev/null +++ b/src/wxcomponents/vant-weapp/count-down/index.json @@ -0,0 +1,3 @@ +{ + "component": true +} diff --git a/src/wxcomponents/vant-weapp/count-down/index.wxml b/src/wxcomponents/vant-weapp/count-down/index.wxml new file mode 100755 index 0000000..e206e16 --- /dev/null +++ b/src/wxcomponents/vant-weapp/count-down/index.wxml @@ -0,0 +1,4 @@ + + + {{ formattedTime }} + diff --git a/src/wxcomponents/vant-weapp/count-down/index.wxss b/src/wxcomponents/vant-weapp/count-down/index.wxss new file mode 100755 index 0000000..8b957f7 --- /dev/null +++ b/src/wxcomponents/vant-weapp/count-down/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-count-down{color:var(--count-down-text-color,#323233);font-size:var(--count-down-font-size,14px);line-height:var(--count-down-line-height,20px)} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/count-down/utils.d.ts b/src/wxcomponents/vant-weapp/count-down/utils.d.ts new file mode 100755 index 0000000..876a6c1 --- /dev/null +++ b/src/wxcomponents/vant-weapp/count-down/utils.d.ts @@ -0,0 +1,10 @@ +export type TimeData = { + days: number; + hours: number; + minutes: number; + seconds: number; + milliseconds: number; +}; +export declare function parseTimeData(time: number): TimeData; +export declare function parseFormat(format: string, timeData: TimeData): string; +export declare function isSameSecond(time1: number, time2: number): boolean; diff --git a/src/wxcomponents/vant-weapp/count-down/utils.js b/src/wxcomponents/vant-weapp/count-down/utils.js new file mode 100755 index 0000000..cbdbd79 --- /dev/null +++ b/src/wxcomponents/vant-weapp/count-down/utils.js @@ -0,0 +1,57 @@ +function padZero(num, targetLength = 2) { + let str = num + ''; + while (str.length < targetLength) { + str = '0' + str; + } + return str; +} +const SECOND = 1000; +const MINUTE = 60 * SECOND; +const HOUR = 60 * MINUTE; +const DAY = 24 * HOUR; +export function parseTimeData(time) { + const days = Math.floor(time / DAY); + const hours = Math.floor((time % DAY) / HOUR); + const minutes = Math.floor((time % HOUR) / MINUTE); + const seconds = Math.floor((time % MINUTE) / SECOND); + const milliseconds = Math.floor(time % SECOND); + return { + days, + hours, + minutes, + seconds, + milliseconds, + }; +} +export function parseFormat(format, timeData) { + const { days } = timeData; + let { hours, minutes, seconds, milliseconds } = timeData; + if (format.indexOf('DD') === -1) { + hours += days * 24; + } + else { + format = format.replace('DD', padZero(days)); + } + if (format.indexOf('HH') === -1) { + minutes += hours * 60; + } + else { + format = format.replace('HH', padZero(hours)); + } + if (format.indexOf('mm') === -1) { + seconds += minutes * 60; + } + else { + format = format.replace('mm', padZero(minutes)); + } + if (format.indexOf('ss') === -1) { + milliseconds += seconds * 1000; + } + else { + format = format.replace('ss', padZero(seconds)); + } + return format.replace('SSS', padZero(milliseconds, 3)); +} +export function isSameSecond(time1, time2) { + return Math.floor(time1 / 1000) === Math.floor(time2 / 1000); +} diff --git a/src/wxcomponents/vant-weapp/datetime-picker/index.d.ts b/src/wxcomponents/vant-weapp/datetime-picker/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/datetime-picker/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/datetime-picker/index.js b/src/wxcomponents/vant-weapp/datetime-picker/index.js new file mode 100755 index 0000000..3334170 --- /dev/null +++ b/src/wxcomponents/vant-weapp/datetime-picker/index.js @@ -0,0 +1,295 @@ +import { VantComponent } from '../common/component'; +import { isDef } from '../common/validator'; +import { pickerProps } from '../picker/shared'; +const currentYear = new Date().getFullYear(); +function isValidDate(date) { + return isDef(date) && !isNaN(new Date(date).getTime()); +} +function range(num, min, max) { + return Math.min(Math.max(num, min), max); +} +function padZero(val) { + return `00${val}`.slice(-2); +} +function times(n, iteratee) { + let index = -1; + const result = Array(n < 0 ? 0 : n); + while (++index < n) { + result[index] = iteratee(index); + } + return result; +} +function getTrueValue(formattedValue) { + if (formattedValue === undefined) { + formattedValue = '1'; + } + while (isNaN(parseInt(formattedValue, 10))) { + formattedValue = formattedValue.slice(1); + } + return parseInt(formattedValue, 10); +} +function getMonthEndDay(year, month) { + return 32 - new Date(year, month - 1, 32).getDate(); +} +const defaultFormatter = (type, value) => value; +VantComponent({ + classes: ['active-class', 'toolbar-class', 'column-class'], + props: Object.assign(Object.assign({}, pickerProps), { value: { + type: null, + observer: 'updateValue', + }, filter: null, type: { + type: String, + value: 'datetime', + observer: 'updateValue', + }, showToolbar: { + type: Boolean, + value: true, + }, formatter: { + type: null, + value: defaultFormatter, + }, minDate: { + type: Number, + value: new Date(currentYear - 10, 0, 1).getTime(), + observer: 'updateValue', + }, maxDate: { + type: Number, + value: new Date(currentYear + 10, 11, 31).getTime(), + observer: 'updateValue', + }, minHour: { + type: Number, + value: 0, + observer: 'updateValue', + }, maxHour: { + type: Number, + value: 23, + observer: 'updateValue', + }, minMinute: { + type: Number, + value: 0, + observer: 'updateValue', + }, maxMinute: { + type: Number, + value: 59, + observer: 'updateValue', + } }), + data: { + innerValue: Date.now(), + columns: [], + }, + methods: { + updateValue() { + const { data } = this; + const val = this.correctValue(data.value); + const isEqual = val === data.innerValue; + this.updateColumnValue(val).then(() => { + if (!isEqual) { + this.$emit('input', val); + } + }); + }, + getPicker() { + if (this.picker == null) { + this.picker = this.selectComponent('.van-datetime-picker'); + const { picker } = this; + const { setColumnValues } = picker; + picker.setColumnValues = (...args) => setColumnValues.apply(picker, [...args, false]); + } + return this.picker; + }, + updateColumns() { + const { formatter = defaultFormatter } = this.data; + const results = this.getOriginColumns().map((column) => ({ + values: column.values.map((value) => formatter(column.type, value)), + })); + return this.set({ columns: results }); + }, + getOriginColumns() { + const { filter } = this.data; + const results = this.getRanges().map(({ type, range }) => { + let values = times(range[1] - range[0] + 1, (index) => { + const value = range[0] + index; + return type === 'year' ? `${value}` : padZero(value); + }); + if (filter) { + values = filter(type, values); + } + return { type, values }; + }); + return results; + }, + getRanges() { + const { data } = this; + if (data.type === 'time') { + return [ + { + type: 'hour', + range: [data.minHour, data.maxHour], + }, + { + type: 'minute', + range: [data.minMinute, data.maxMinute], + }, + ]; + } + const { maxYear, maxDate, maxMonth, maxHour, maxMinute, } = this.getBoundary('max', data.innerValue); + const { minYear, minDate, minMonth, minHour, minMinute, } = this.getBoundary('min', data.innerValue); + const result = [ + { + type: 'year', + range: [minYear, maxYear], + }, + { + type: 'month', + range: [minMonth, maxMonth], + }, + { + type: 'day', + range: [minDate, maxDate], + }, + { + type: 'hour', + range: [minHour, maxHour], + }, + { + type: 'minute', + range: [minMinute, maxMinute], + }, + ]; + if (data.type === 'date') + result.splice(3, 2); + if (data.type === 'year-month') + result.splice(2, 3); + return result; + }, + correctValue(value) { + const { data } = this; + // validate value + const isDateType = data.type !== 'time'; + if (isDateType && !isValidDate(value)) { + value = data.minDate; + } + else if (!isDateType && !value) { + const { minHour } = data; + value = `${padZero(minHour)}:00`; + } + // time type + if (!isDateType) { + let [hour, minute] = value.split(':'); + hour = padZero(range(hour, data.minHour, data.maxHour)); + minute = padZero(range(minute, data.minMinute, data.maxMinute)); + return `${hour}:${minute}`; + } + // date type + value = Math.max(value, data.minDate); + value = Math.min(value, data.maxDate); + return value; + }, + getBoundary(type, innerValue) { + const value = new Date(innerValue); + const boundary = new Date(this.data[`${type}Date`]); + const year = boundary.getFullYear(); + let month = 1; + let date = 1; + let hour = 0; + let minute = 0; + if (type === 'max') { + month = 12; + date = getMonthEndDay(value.getFullYear(), value.getMonth() + 1); + hour = 23; + minute = 59; + } + if (value.getFullYear() === year) { + month = boundary.getMonth() + 1; + if (value.getMonth() + 1 === month) { + date = boundary.getDate(); + if (value.getDate() === date) { + hour = boundary.getHours(); + if (value.getHours() === hour) { + minute = boundary.getMinutes(); + } + } + } + } + return { + [`${type}Year`]: year, + [`${type}Month`]: month, + [`${type}Date`]: date, + [`${type}Hour`]: hour, + [`${type}Minute`]: minute, + }; + }, + onCancel() { + this.$emit('cancel'); + }, + onConfirm() { + this.$emit('confirm', this.data.innerValue); + }, + onChange() { + const { data } = this; + let value; + const picker = this.getPicker(); + const originColumns = this.getOriginColumns(); + if (data.type === 'time') { + const indexes = picker.getIndexes(); + value = `${+originColumns[0].values[indexes[0]]}:${+originColumns[1] + .values[indexes[1]]}`; + } + else { + const indexes = picker.getIndexes(); + const values = indexes.map((value, index) => originColumns[index].values[value]); + const year = getTrueValue(values[0]); + const month = getTrueValue(values[1]); + const maxDate = getMonthEndDay(year, month); + let date = getTrueValue(values[2]); + if (data.type === 'year-month') { + date = 1; + } + date = date > maxDate ? maxDate : date; + let hour = 0; + let minute = 0; + if (data.type === 'datetime') { + hour = getTrueValue(values[3]); + minute = getTrueValue(values[4]); + } + value = new Date(year, month - 1, date, hour, minute); + } + value = this.correctValue(value); + this.updateColumnValue(value).then(() => { + this.$emit('input', value); + this.$emit('change', picker); + }); + }, + updateColumnValue(value) { + let values = []; + const { type } = this.data; + const formatter = this.data.formatter || defaultFormatter; + const picker = this.getPicker(); + if (type === 'time') { + const pair = value.split(':'); + values = [formatter('hour', pair[0]), formatter('minute', pair[1])]; + } + else { + const date = new Date(value); + values = [ + formatter('year', `${date.getFullYear()}`), + formatter('month', padZero(date.getMonth() + 1)), + ]; + if (type === 'date') { + values.push(formatter('day', padZero(date.getDate()))); + } + if (type === 'datetime') { + values.push(formatter('day', padZero(date.getDate())), formatter('hour', padZero(date.getHours())), formatter('minute', padZero(date.getMinutes()))); + } + } + return this.set({ innerValue: value }) + .then(() => this.updateColumns()) + .then(() => picker.setValues(values)); + }, + }, + created() { + const innerValue = this.correctValue(this.data.value); + this.updateColumnValue(innerValue).then(() => { + this.$emit('input', innerValue); + }); + }, +}); diff --git a/src/wxcomponents/vant-weapp/datetime-picker/index.json b/src/wxcomponents/vant-weapp/datetime-picker/index.json new file mode 100755 index 0000000..a778e91 --- /dev/null +++ b/src/wxcomponents/vant-weapp/datetime-picker/index.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "van-picker": "../picker/index" + } +} diff --git a/src/wxcomponents/vant-weapp/datetime-picker/index.wxml b/src/wxcomponents/vant-weapp/datetime-picker/index.wxml new file mode 100755 index 0000000..ade2202 --- /dev/null +++ b/src/wxcomponents/vant-weapp/datetime-picker/index.wxml @@ -0,0 +1,16 @@ + diff --git a/src/wxcomponents/vant-weapp/datetime-picker/index.wxss b/src/wxcomponents/vant-weapp/datetime-picker/index.wxss new file mode 100755 index 0000000..99694d6 --- /dev/null +++ b/src/wxcomponents/vant-weapp/datetime-picker/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss'; \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/definitions/index.d.ts b/src/wxcomponents/vant-weapp/definitions/index.d.ts new file mode 100755 index 0000000..d0554f6 --- /dev/null +++ b/src/wxcomponents/vant-weapp/definitions/index.d.ts @@ -0,0 +1,28 @@ +/// +interface VantComponentInstance { + parent: WechatMiniprogram.Component.TrivialInstance; + children: WechatMiniprogram.Component.TrivialInstance[]; + index: number; + $emit: (name: string, detail?: unknown, options?: WechatMiniprogram.Component.TriggerEventOption) => void; +} +export type VantComponentOptions = { + data?: Data; + field?: boolean; + classes?: string[]; + mixins?: string[]; + props?: Props; + relation?: { + relations: Record; + mixin: string; + }; + watch?: Record any>; + methods?: Methods; + beforeCreate?: () => void; + created?: () => void; + mounted?: () => void; + destroyed?: () => void; +} & ThisType, Props, Methods> & Record>; +export {}; diff --git a/src/wxcomponents/vant-weapp/definitions/index.js b/src/wxcomponents/vant-weapp/definitions/index.js new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/definitions/index.js @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/dialog/dialog.d.ts b/src/wxcomponents/vant-weapp/dialog/dialog.d.ts new file mode 100755 index 0000000..db2da5f --- /dev/null +++ b/src/wxcomponents/vant-weapp/dialog/dialog.d.ts @@ -0,0 +1,55 @@ +/// +/// +export type Action = 'confirm' | 'cancel' | 'overlay'; +type DialogContext = WechatMiniprogram.Page.TrivialInstance | WechatMiniprogram.Component.TrivialInstance; +interface DialogOptions { + lang?: string; + show?: boolean; + title?: string; + width?: string | number | null; + zIndex?: number; + theme?: string; + context?: (() => DialogContext) | DialogContext; + message?: string; + overlay?: boolean; + selector?: string; + ariaLabel?: string; + /** + * @deprecated use custom-class instead + */ + className?: string; + customStyle?: string; + transition?: string; + /** + * @deprecated use beforeClose instead + */ + asyncClose?: boolean; + beforeClose?: null | ((action: Action) => Promise | void); + businessId?: number; + sessionFrom?: string; + overlayStyle?: string; + appParameter?: string; + messageAlign?: string; + sendMessageImg?: string; + showMessageCard?: boolean; + sendMessagePath?: string; + sendMessageTitle?: string; + confirmButtonText?: string; + cancelButtonText?: string; + showConfirmButton?: boolean; + showCancelButton?: boolean; + closeOnClickOverlay?: boolean; + confirmButtonOpenType?: string; +} +declare const Dialog: { + (options: DialogOptions): Promise; + alert(options: DialogOptions): Promise; + confirm(options: DialogOptions): Promise; + close(): void; + stopLoading(): void; + currentOptions: DialogOptions; + defaultOptions: DialogOptions; + setDefaultOptions(options: DialogOptions): void; + resetDefaultOptions(): void; +}; +export default Dialog; diff --git a/src/wxcomponents/vant-weapp/dialog/dialog.js b/src/wxcomponents/vant-weapp/dialog/dialog.js new file mode 100755 index 0000000..a96ec08 --- /dev/null +++ b/src/wxcomponents/vant-weapp/dialog/dialog.js @@ -0,0 +1,77 @@ +let queue = []; +const defaultOptions = { + show: false, + title: '', + width: null, + theme: 'default', + message: '', + zIndex: 100, + overlay: true, + selector: '#van-dialog', + className: '', + asyncClose: false, + beforeClose: null, + transition: 'scale', + customStyle: '', + messageAlign: '', + overlayStyle: '', + confirmButtonText: '确认', + cancelButtonText: '取消', + showConfirmButton: true, + showCancelButton: false, + closeOnClickOverlay: false, + confirmButtonOpenType: '', +}; +let currentOptions = Object.assign({}, defaultOptions); +function getContext() { + const pages = getCurrentPages(); + return pages[pages.length - 1]; +} +const Dialog = (options) => { + options = Object.assign(Object.assign({}, currentOptions), options); + return new Promise((resolve, reject) => { + const context = (typeof options.context === 'function' + ? options.context() + : options.context) || getContext(); + const dialog = context.selectComponent(options.selector); + delete options.context; + delete options.selector; + if (dialog) { + dialog.setData(Object.assign({ callback: (action, instance) => { + action === 'confirm' ? resolve(instance) : reject(instance); + } }, options)); + wx.nextTick(() => { + dialog.setData({ show: true }); + }); + queue.push(dialog); + } + else { + console.warn('未找到 van-dialog 节点,请确认 selector 及 context 是否正确'); + } + }); +}; +Dialog.alert = (options) => Dialog(options); +Dialog.confirm = (options) => Dialog(Object.assign({ showCancelButton: true }, options)); +Dialog.close = () => { + queue.forEach((dialog) => { + dialog.close(); + }); + queue = []; +}; +Dialog.stopLoading = () => { + queue.forEach((dialog) => { + dialog.stopLoading(); + }); +}; +Dialog.currentOptions = currentOptions; +Dialog.defaultOptions = defaultOptions; +Dialog.setDefaultOptions = (options) => { + currentOptions = Object.assign(Object.assign({}, currentOptions), options); + Dialog.currentOptions = currentOptions; +}; +Dialog.resetDefaultOptions = () => { + currentOptions = Object.assign({}, defaultOptions); + Dialog.currentOptions = currentOptions; +}; +Dialog.resetDefaultOptions(); +export default Dialog; diff --git a/src/wxcomponents/vant-weapp/dialog/index.d.ts b/src/wxcomponents/vant-weapp/dialog/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/dialog/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/dialog/index.js b/src/wxcomponents/vant-weapp/dialog/index.js new file mode 100755 index 0000000..04c57a6 --- /dev/null +++ b/src/wxcomponents/vant-weapp/dialog/index.js @@ -0,0 +1,126 @@ +import { VantComponent } from '../common/component'; +import { button } from '../mixins/button'; +import { GRAY, RED } from '../common/color'; +import { toPromise } from '../common/utils'; +VantComponent({ + mixins: [button], + classes: ['cancle-button-class', 'confirm-button-class'], + props: { + show: { + type: Boolean, + observer(show) { + !show && this.stopLoading(); + }, + }, + title: String, + message: String, + theme: { + type: String, + value: 'default', + }, + confirmButtonId: String, + className: String, + customStyle: String, + asyncClose: Boolean, + messageAlign: String, + beforeClose: null, + overlayStyle: String, + useSlot: Boolean, + useTitleSlot: Boolean, + useConfirmButtonSlot: Boolean, + useCancelButtonSlot: Boolean, + showCancelButton: Boolean, + closeOnClickOverlay: Boolean, + confirmButtonOpenType: String, + width: null, + zIndex: { + type: Number, + value: 2000, + }, + confirmButtonText: { + type: String, + value: '确认', + }, + cancelButtonText: { + type: String, + value: '取消', + }, + confirmButtonColor: { + type: String, + value: RED, + }, + cancelButtonColor: { + type: String, + value: GRAY, + }, + showConfirmButton: { + type: Boolean, + value: true, + }, + overlay: { + type: Boolean, + value: true, + }, + transition: { + type: String, + value: 'scale', + }, + }, + data: { + loading: { + confirm: false, + cancel: false, + }, + callback: (() => { }), + }, + methods: { + onConfirm() { + this.handleAction('confirm'); + }, + onCancel() { + this.handleAction('cancel'); + }, + onClickOverlay() { + this.close('overlay'); + }, + close(action) { + this.setData({ show: false }); + wx.nextTick(() => { + this.$emit('close', action); + const { callback } = this.data; + if (callback) { + callback(action, this); + } + }); + }, + stopLoading() { + this.setData({ + loading: { + confirm: false, + cancel: false, + }, + }); + }, + handleAction(action) { + this.$emit(action, { dialog: this }); + const { asyncClose, beforeClose } = this.data; + if (!asyncClose && !beforeClose) { + this.close(action); + return; + } + this.setData({ + [`loading.${action}`]: true, + }); + if (beforeClose) { + toPromise(beforeClose(action)).then((value) => { + if (value) { + this.close(action); + } + else { + this.stopLoading(); + } + }); + } + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/dialog/index.json b/src/wxcomponents/vant-weapp/dialog/index.json new file mode 100755 index 0000000..43417fc --- /dev/null +++ b/src/wxcomponents/vant-weapp/dialog/index.json @@ -0,0 +1,9 @@ +{ + "component": true, + "usingComponents": { + "van-popup": "../popup/index", + "van-button": "../button/index", + "van-goods-action": "../goods-action/index", + "van-goods-action-button": "../goods-action-button/index" + } +} diff --git a/src/wxcomponents/vant-weapp/dialog/index.wxml b/src/wxcomponents/vant-weapp/dialog/index.wxml new file mode 100755 index 0000000..8e0bb22 --- /dev/null +++ b/src/wxcomponents/vant-weapp/dialog/index.wxml @@ -0,0 +1,122 @@ + + + + + + {{ title }} + + + + + {{ message }} + + + + + {{ cancelButtonText }} + + + {{ confirmButtonText }} + + + + + + + + + {{ cancelButtonText }} + + + + + + + + {{ confirmButtonText }} + + + + diff --git a/src/wxcomponents/vant-weapp/dialog/index.wxss b/src/wxcomponents/vant-weapp/dialog/index.wxss new file mode 100755 index 0000000..507a789 --- /dev/null +++ b/src/wxcomponents/vant-weapp/dialog/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-dialog{background-color:var(--dialog-background-color,#fff);border-radius:var(--dialog-border-radius,16px);font-size:var(--dialog-font-size,16px);overflow:hidden;top:45%!important;width:var(--dialog-width,320px)}@media (max-width:321px){.van-dialog{width:var(--dialog-small-screen-width,90%)}}.van-dialog__header{font-weight:var(--dialog-header-font-weight,500);line-height:var(--dialog-header-line-height,24px);padding-top:var(--dialog-header-padding-top,24px);text-align:center}.van-dialog__header--isolated{padding:var(--dialog-header-isolated-padding,24px 0)}.van-dialog__message{-webkit-overflow-scrolling:touch;font-size:var(--dialog-message-font-size,14px);line-height:var(--dialog-message-line-height,20px);max-height:var(--dialog-message-max-height,60vh);overflow-y:auto;padding:var(--dialog-message-padding,24px);text-align:center}.van-dialog__message-text{word-wrap:break-word}.van-dialog__message--hasTitle{color:var(--dialog-has-title-message-text-color,#646566);padding-top:var(--dialog-has-title-message-padding-top,8px)}.van-dialog__message--round-button{color:#323233;padding-bottom:16px}.van-dialog__message--left{text-align:left}.van-dialog__message--right{text-align:right}.van-dialog__message--justify{text-align:justify}.van-dialog__footer{display:flex}.van-dialog__footer--round-button{padding:8px 24px 16px!important;position:relative!important}.van-dialog__button{flex:1}.van-dialog__cancel,.van-dialog__confirm{border:0!important}.van-dialog-bounce-enter{opacity:0;transform:translate3d(-50%,-50%,0) scale(.7)}.van-dialog-bounce-leave-active{opacity:0;transform:translate3d(-50%,-50%,0) scale(.9)} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/divider/index.d.ts b/src/wxcomponents/vant-weapp/divider/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/divider/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/divider/index.js b/src/wxcomponents/vant-weapp/divider/index.js new file mode 100755 index 0000000..9596edd --- /dev/null +++ b/src/wxcomponents/vant-weapp/divider/index.js @@ -0,0 +1,12 @@ +import { VantComponent } from '../common/component'; +VantComponent({ + props: { + dashed: Boolean, + hairline: Boolean, + contentPosition: String, + fontSize: String, + borderColor: String, + textColor: String, + customStyle: String, + }, +}); diff --git a/src/wxcomponents/vant-weapp/divider/index.json b/src/wxcomponents/vant-weapp/divider/index.json new file mode 100755 index 0000000..a89ef4d --- /dev/null +++ b/src/wxcomponents/vant-weapp/divider/index.json @@ -0,0 +1,4 @@ +{ + "component": true, + "usingComponents": {} +} diff --git a/src/wxcomponents/vant-weapp/divider/index.wxml b/src/wxcomponents/vant-weapp/divider/index.wxml new file mode 100755 index 0000000..f6a5a45 --- /dev/null +++ b/src/wxcomponents/vant-weapp/divider/index.wxml @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/wxcomponents/vant-weapp/divider/index.wxs b/src/wxcomponents/vant-weapp/divider/index.wxs new file mode 100755 index 0000000..215b14f --- /dev/null +++ b/src/wxcomponents/vant-weapp/divider/index.wxs @@ -0,0 +1,18 @@ +/* eslint-disable */ +var style = require('../wxs/style.wxs'); +var addUnit = require('../wxs/add-unit.wxs'); + +function rootStyle(data) { + return style([ + { + 'border-color': data.borderColor, + color: data.textColor, + 'font-size': addUnit(data.fontSize), + }, + data.customStyle, + ]); +} + +module.exports = { + rootStyle: rootStyle, +}; diff --git a/src/wxcomponents/vant-weapp/divider/index.wxss b/src/wxcomponents/vant-weapp/divider/index.wxss new file mode 100755 index 0000000..e91dc44 --- /dev/null +++ b/src/wxcomponents/vant-weapp/divider/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-divider{align-items:center;border:0 solid var(--divider-border-color,#ebedf0);color:var(--divider-text-color,#969799);display:flex;font-size:var(--divider-font-size,14px);line-height:var(--divider-line-height,24px);margin:var(--divider-margin,16px 0)}.van-divider:after,.van-divider:before{border-color:inherit;border-style:inherit;border-width:1px 0 0;box-sizing:border-box;display:block;flex:1;height:1px}.van-divider:before{content:""}.van-divider--hairline:after,.van-divider--hairline:before{transform:scaleY(.5)}.van-divider--dashed{border-style:dashed}.van-divider--center:before,.van-divider--left:before,.van-divider--right:before{margin-right:var(--divider-content-padding,16px)}.van-divider--center:after,.van-divider--left:after,.van-divider--right:after{content:"";margin-left:var(--divider-content-padding,16px)}.van-divider--left:before{max-width:var(--divider-content-left-width,10%)}.van-divider--right:after{max-width:var(--divider-content-right-width,10%)} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/dropdown-item/index.d.ts b/src/wxcomponents/vant-weapp/dropdown-item/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/dropdown-item/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/dropdown-item/index.js b/src/wxcomponents/vant-weapp/dropdown-item/index.js new file mode 100755 index 0000000..fd61a47 --- /dev/null +++ b/src/wxcomponents/vant-weapp/dropdown-item/index.js @@ -0,0 +1,130 @@ +import { useParent } from '../common/relation'; +import { VantComponent } from '../common/component'; +VantComponent({ + classes: ['item-title-class'], + field: true, + relation: useParent('dropdown-menu', function () { + this.updateDataFromParent(); + }), + props: { + value: { + type: null, + observer: 'rerender', + }, + title: { + type: String, + observer: 'rerender', + }, + disabled: Boolean, + titleClass: { + type: String, + observer: 'rerender', + }, + options: { + type: Array, + value: [], + observer: 'rerender', + }, + popupStyle: String, + useBeforeToggle: { + type: Boolean, + value: false, + }, + rootPortal: { + type: Boolean, + value: false, + }, + }, + data: { + transition: true, + showPopup: false, + showWrapper: false, + displayTitle: '', + safeAreaTabBar: false, + }, + methods: { + rerender() { + wx.nextTick(() => { + var _a; + (_a = this.parent) === null || _a === void 0 ? void 0 : _a.updateItemListData(); + }); + }, + updateDataFromParent() { + if (this.parent) { + const { overlay, duration, activeColor, closeOnClickOverlay, direction, safeAreaTabBar, } = this.parent.data; + this.setData({ + overlay, + duration, + activeColor, + closeOnClickOverlay, + direction, + safeAreaTabBar, + }); + } + }, + onOpen() { + this.$emit('open'); + }, + onOpened() { + this.$emit('opened'); + }, + onClose() { + this.$emit('close'); + }, + onClosed() { + this.$emit('closed'); + this.setData({ showWrapper: false }); + }, + onOptionTap(event) { + const { option } = event.currentTarget.dataset; + const { value } = option; + const shouldEmitChange = this.data.value !== value; + this.setData({ showPopup: false, value }); + this.$emit('close'); + this.rerender(); + if (shouldEmitChange) { + this.$emit('change', value); + } + }, + toggle(show, options = {}) { + const { showPopup } = this.data; + if (typeof show !== 'boolean') { + show = !showPopup; + } + if (show === showPopup) { + return; + } + this.onBeforeToggle(show).then((status) => { + var _a; + if (!status) { + return; + } + this.setData({ + transition: !options.immediate, + showPopup: show, + }); + if (show) { + (_a = this.parent) === null || _a === void 0 ? void 0 : _a.getChildWrapperStyle().then((wrapperStyle) => { + this.setData({ wrapperStyle, showWrapper: true }); + this.rerender(); + }); + } + else { + this.rerender(); + } + }); + }, + onBeforeToggle(status) { + const { useBeforeToggle } = this.data; + if (!useBeforeToggle) { + return Promise.resolve(true); + } + return new Promise((resolve) => { + this.$emit('before-toggle', { + status, + callback: (value) => resolve(value), + }); + }); + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/dropdown-item/index.json b/src/wxcomponents/vant-weapp/dropdown-item/index.json new file mode 100755 index 0000000..88d5409 --- /dev/null +++ b/src/wxcomponents/vant-weapp/dropdown-item/index.json @@ -0,0 +1,8 @@ +{ + "component": true, + "usingComponents": { + "van-popup": "../popup/index", + "van-cell": "../cell/index", + "van-icon": "../icon/index" + } +} diff --git a/src/wxcomponents/vant-weapp/dropdown-item/index.wxml b/src/wxcomponents/vant-weapp/dropdown-item/index.wxml new file mode 100755 index 0000000..63904f4 --- /dev/null +++ b/src/wxcomponents/vant-weapp/dropdown-item/index.wxml @@ -0,0 +1,50 @@ + + + + + + + {{ item.text }} + + + + + + + diff --git a/src/wxcomponents/vant-weapp/dropdown-item/index.wxss b/src/wxcomponents/vant-weapp/dropdown-item/index.wxss new file mode 100755 index 0000000..80505e9 --- /dev/null +++ b/src/wxcomponents/vant-weapp/dropdown-item/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-dropdown-item{left:0;overflow:hidden;position:fixed;right:0}.van-dropdown-item__option{text-align:left}.van-dropdown-item__option--active .van-dropdown-item__icon,.van-dropdown-item__option--active .van-dropdown-item__title{color:var(--dropdown-menu-option-active-color,#ee0a24)}.van-dropdown-item--up{top:0}.van-dropdown-item--down{bottom:0}.van-dropdown-item__icon{display:block;line-height:inherit} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/dropdown-item/shared.d.ts b/src/wxcomponents/vant-weapp/dropdown-item/shared.d.ts new file mode 100755 index 0000000..774eb4c --- /dev/null +++ b/src/wxcomponents/vant-weapp/dropdown-item/shared.d.ts @@ -0,0 +1,5 @@ +export interface Option { + text: string; + value: string | number; + icon: string; +} diff --git a/src/wxcomponents/vant-weapp/dropdown-item/shared.js b/src/wxcomponents/vant-weapp/dropdown-item/shared.js new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/dropdown-item/shared.js @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/dropdown-menu/index.d.ts b/src/wxcomponents/vant-weapp/dropdown-menu/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/dropdown-menu/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/dropdown-menu/index.js b/src/wxcomponents/vant-weapp/dropdown-menu/index.js new file mode 100755 index 0000000..9858ab3 --- /dev/null +++ b/src/wxcomponents/vant-weapp/dropdown-menu/index.js @@ -0,0 +1,117 @@ +import { VantComponent } from '../common/component'; +import { useChildren } from '../common/relation'; +import { addUnit, getRect, getSystemInfoSync } from '../common/utils'; +let ARRAY = []; +VantComponent({ + field: true, + classes: ['title-class'], + relation: useChildren('dropdown-item', function () { + this.updateItemListData(); + }), + props: { + activeColor: { + type: String, + observer: 'updateChildrenData', + }, + overlay: { + type: Boolean, + value: true, + observer: 'updateChildrenData', + }, + zIndex: { + type: Number, + value: 10, + }, + duration: { + type: Number, + value: 200, + observer: 'updateChildrenData', + }, + direction: { + type: String, + value: 'down', + observer: 'updateChildrenData', + }, + safeAreaTabBar: { + type: Boolean, + value: false, + }, + closeOnClickOverlay: { + type: Boolean, + value: true, + observer: 'updateChildrenData', + }, + closeOnClickOutside: { + type: Boolean, + value: true, + }, + }, + data: { + itemListData: [], + }, + beforeCreate() { + const { windowHeight } = getSystemInfoSync(); + this.windowHeight = windowHeight; + ARRAY.push(this); + }, + destroyed() { + ARRAY = ARRAY.filter((item) => item !== this); + }, + methods: { + updateItemListData() { + this.setData({ + itemListData: this.children.map((child) => child.data), + }); + }, + updateChildrenData() { + this.children.forEach((child) => { + child.updateDataFromParent(); + }); + }, + toggleItem(active) { + this.children.forEach((item, index) => { + const { showPopup } = item.data; + if (index === active) { + item.toggle(); + } + else if (showPopup) { + item.toggle(false, { immediate: true }); + } + }); + }, + close() { + this.children.forEach((child) => { + child.toggle(false, { immediate: true }); + }); + }, + getChildWrapperStyle() { + const { zIndex, direction } = this.data; + return getRect(this, '.van-dropdown-menu').then((rect) => { + const { top = 0, bottom = 0 } = rect; + const offset = direction === 'down' ? bottom : this.windowHeight - top; + let wrapperStyle = `z-index: ${zIndex};`; + if (direction === 'down') { + wrapperStyle += `top: ${addUnit(offset)};`; + } + else { + wrapperStyle += `bottom: ${addUnit(offset)};`; + } + return wrapperStyle; + }); + }, + onTitleTap(event) { + const { index } = event.currentTarget.dataset; + const child = this.children[index]; + if (!child.data.disabled) { + ARRAY.forEach((menuItem) => { + if (menuItem && + menuItem.data.closeOnClickOutside && + menuItem !== this) { + menuItem.close(); + } + }); + this.toggleItem(index); + } + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/dropdown-menu/index.json b/src/wxcomponents/vant-weapp/dropdown-menu/index.json new file mode 100755 index 0000000..467ce29 --- /dev/null +++ b/src/wxcomponents/vant-weapp/dropdown-menu/index.json @@ -0,0 +1,3 @@ +{ + "component": true +} diff --git a/src/wxcomponents/vant-weapp/dropdown-menu/index.wxml b/src/wxcomponents/vant-weapp/dropdown-menu/index.wxml new file mode 100755 index 0000000..ec165a9 --- /dev/null +++ b/src/wxcomponents/vant-weapp/dropdown-menu/index.wxml @@ -0,0 +1,23 @@ + + + + + + + + {{ computed.displayTitle(item) }} + + + + + + diff --git a/src/wxcomponents/vant-weapp/dropdown-menu/index.wxs b/src/wxcomponents/vant-weapp/dropdown-menu/index.wxs new file mode 100755 index 0000000..6538854 --- /dev/null +++ b/src/wxcomponents/vant-weapp/dropdown-menu/index.wxs @@ -0,0 +1,16 @@ +/* eslint-disable */ +function displayTitle(item) { + if (item.title) { + return item.title; + } + + var match = item.options.filter(function(option) { + return option.value === item.value; + }); + var displayTitle = match.length ? match[0].text : ''; + return displayTitle; +} + +module.exports = { + displayTitle: displayTitle +}; diff --git a/src/wxcomponents/vant-weapp/dropdown-menu/index.wxss b/src/wxcomponents/vant-weapp/dropdown-menu/index.wxss new file mode 100755 index 0000000..dba000e --- /dev/null +++ b/src/wxcomponents/vant-weapp/dropdown-menu/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-dropdown-menu{background-color:var(--dropdown-menu-background-color,#fff);box-shadow:var(--dropdown-menu-box-shadow,0 2px 12px hsla(210,1%,40%,.12));display:flex;height:var(--dropdown-menu-height,50px);-webkit-user-select:none;user-select:none}.van-dropdown-menu__item{align-items:center;display:flex;flex:1;justify-content:center;min-width:0}.van-dropdown-menu__item:active{opacity:.7}.van-dropdown-menu__item--disabled:active{opacity:1}.van-dropdown-menu__item--disabled .van-dropdown-menu__title{color:var(--dropdown-menu-title-disabled-text-color,#969799)}.van-dropdown-menu__title{box-sizing:border-box;color:var(--dropdown-menu-title-text-color,#323233);font-size:var(--dropdown-menu-title-font-size,15px);line-height:var(--dropdown-menu-title-line-height,18px);max-width:100%;padding:var(--dropdown-menu-title-padding,0 24px 0 8px);position:relative}.van-dropdown-menu__title:after{border-color:transparent transparent currentcolor currentcolor;border-style:solid;border-width:3px;content:"";margin-top:-5px;opacity:.8;position:absolute;right:11px;top:50%;transform:rotate(-45deg)}.van-dropdown-menu__title--active{color:var(--dropdown-menu-title-active-text-color,#ee0a24)}.van-dropdown-menu__title--down:after{margin-top:-1px;transform:rotate(135deg)} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/empty/index.d.ts b/src/wxcomponents/vant-weapp/empty/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/empty/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/empty/index.js b/src/wxcomponents/vant-weapp/empty/index.js new file mode 100755 index 0000000..842e1bb --- /dev/null +++ b/src/wxcomponents/vant-weapp/empty/index.js @@ -0,0 +1,10 @@ +import { VantComponent } from '../common/component'; +VantComponent({ + props: { + description: String, + image: { + type: String, + value: 'default', + }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/empty/index.json b/src/wxcomponents/vant-weapp/empty/index.json new file mode 100755 index 0000000..a89ef4d --- /dev/null +++ b/src/wxcomponents/vant-weapp/empty/index.json @@ -0,0 +1,4 @@ +{ + "component": true, + "usingComponents": {} +} diff --git a/src/wxcomponents/vant-weapp/empty/index.wxml b/src/wxcomponents/vant-weapp/empty/index.wxml new file mode 100755 index 0000000..9c7b719 --- /dev/null +++ b/src/wxcomponents/vant-weapp/empty/index.wxml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + {{ description }} + + + + + + diff --git a/src/wxcomponents/vant-weapp/empty/index.wxs b/src/wxcomponents/vant-weapp/empty/index.wxs new file mode 100755 index 0000000..cf92ece --- /dev/null +++ b/src/wxcomponents/vant-weapp/empty/index.wxs @@ -0,0 +1,15 @@ +/* eslint-disable */ +var PRESETS = ['error', 'search', 'default', 'network']; + +function imageUrl(image) { + if (PRESETS.indexOf(image) !== -1) { + return 'https://img.yzcdn.cn/vant/empty-image-' + image + '.png'; + } + + return image; +} + +module.exports = { + imageUrl: imageUrl, +}; + diff --git a/src/wxcomponents/vant-weapp/empty/index.wxss b/src/wxcomponents/vant-weapp/empty/index.wxss new file mode 100755 index 0000000..0fb74fe --- /dev/null +++ b/src/wxcomponents/vant-weapp/empty/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-empty{align-items:center;box-sizing:border-box;display:flex;flex-direction:column;justify-content:center;padding:32px 0}.van-empty__image{height:160px;width:160px}.van-empty__image:empty{display:none}.van-empty__image__img{height:100%;width:100%}.van-empty__image:not(:empty)+.van-empty__image{display:none}.van-empty__description{color:#969799;font-size:14px;line-height:20px;margin-top:16px;padding:0 60px}.van-empty__description:empty,.van-empty__description:not(:empty)+.van-empty__description{display:none}.van-empty__bottom{margin-top:24px} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/field/index.d.ts b/src/wxcomponents/vant-weapp/field/index.d.ts new file mode 100755 index 0000000..cb0ff5c --- /dev/null +++ b/src/wxcomponents/vant-weapp/field/index.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/src/wxcomponents/vant-weapp/field/index.js b/src/wxcomponents/vant-weapp/field/index.js new file mode 100755 index 0000000..dba92e0 --- /dev/null +++ b/src/wxcomponents/vant-weapp/field/index.js @@ -0,0 +1,123 @@ +import { nextTick } from '../common/utils'; +import { VantComponent } from '../common/component'; +import { commonProps, inputProps, textareaProps } from './props'; +VantComponent({ + field: true, + classes: ['input-class', 'right-icon-class', 'label-class'], + props: Object.assign(Object.assign(Object.assign(Object.assign({}, commonProps), inputProps), textareaProps), { size: String, icon: String, label: String, error: Boolean, center: Boolean, isLink: Boolean, leftIcon: String, rightIcon: String, autosize: null, required: Boolean, iconClass: String, clickable: Boolean, inputAlign: String, customStyle: String, errorMessage: String, arrowDirection: String, showWordLimit: Boolean, errorMessageAlign: String, readonly: { + type: Boolean, + observer: 'setShowClear', + }, clearable: { + type: Boolean, + observer: 'setShowClear', + }, clearTrigger: { + type: String, + value: 'focus', + }, border: { + type: Boolean, + value: true, + }, titleWidth: { + type: String, + value: '6.2em', + }, clearIcon: { + type: String, + value: 'clear', + }, extraEventParams: { + type: Boolean, + value: false, + } }), + data: { + focused: false, + innerValue: '', + showClear: false, + }, + created() { + this.value = this.data.value; + this.setData({ innerValue: this.value }); + }, + methods: { + formatValue(value) { + const { maxlength } = this.data; + if (maxlength !== -1 && value.length > maxlength) { + return value.slice(0, maxlength); + } + return value; + }, + onInput(event) { + const { value = '' } = event.detail || {}; + const formatValue = this.formatValue(value); + this.value = formatValue; + this.setShowClear(); + return this.emitChange(Object.assign(Object.assign({}, event.detail), { value: formatValue })); + }, + onFocus(event) { + this.focused = true; + this.setShowClear(); + this.$emit('focus', event.detail); + }, + onBlur(event) { + this.focused = false; + this.setShowClear(); + this.$emit('blur', event.detail); + }, + onClickIcon() { + this.$emit('click-icon'); + }, + onClickInput(event) { + this.$emit('click-input', event.detail); + }, + onClear() { + this.setData({ innerValue: '' }); + this.value = ''; + this.setShowClear(); + nextTick(() => { + this.emitChange({ value: '' }); + this.$emit('clear', ''); + }); + }, + onConfirm(event) { + const { value = '' } = event.detail || {}; + this.value = value; + this.setShowClear(); + this.$emit('confirm', value); + }, + setValue(value) { + this.value = value; + this.setShowClear(); + if (value === '') { + this.setData({ innerValue: '' }); + } + this.emitChange({ value }); + }, + onLineChange(event) { + this.$emit('linechange', event.detail); + }, + onKeyboardHeightChange(event) { + this.$emit('keyboardheightchange', event.detail); + }, + emitChange(detail) { + const { extraEventParams } = this.data; + this.setData({ value: detail.value }); + let result; + const data = extraEventParams + ? Object.assign(Object.assign({}, detail), { callback: (data) => { + result = data; + } }) : detail.value; + this.$emit('input', data); + this.$emit('change', data); + return result; + }, + setShowClear() { + const { clearable, readonly, clearTrigger } = this.data; + const { focused, value } = this; + let showClear = false; + if (clearable && !readonly) { + const hasValue = !!value; + const trigger = clearTrigger === 'always' || (clearTrigger === 'focus' && focused); + showClear = hasValue && trigger; + } + this.setData({ showClear }); + }, + noop() { }, + }, +}); diff --git a/src/wxcomponents/vant-weapp/field/index.json b/src/wxcomponents/vant-weapp/field/index.json new file mode 100755 index 0000000..5906c50 --- /dev/null +++ b/src/wxcomponents/vant-weapp/field/index.json @@ -0,0 +1,7 @@ +{ + "component": true, + "usingComponents": { + "van-cell": "../cell/index", + "van-icon": "../icon/index" + } +} diff --git a/src/wxcomponents/vant-weapp/field/index.wxml b/src/wxcomponents/vant-weapp/field/index.wxml new file mode 100755 index 0000000..6018993 --- /dev/null +++ b/src/wxcomponents/vant-weapp/field/index.wxml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wxcomponents/vant-weapp/field/index.wxs b/src/wxcomponents/vant-weapp/field/index.wxs new file mode 100755 index 0000000..78575b9 --- /dev/null +++ b/src/wxcomponents/vant-weapp/field/index.wxs @@ -0,0 +1,18 @@ +/* eslint-disable */ +var style = require('../wxs/style.wxs'); +var addUnit = require('../wxs/add-unit.wxs'); + +function inputStyle(autosize) { + if (autosize && autosize.constructor === 'Object') { + return style({ + 'min-height': addUnit(autosize.minHeight), + 'max-height': addUnit(autosize.maxHeight), + }); + } + + return ''; +} + +module.exports = { + inputStyle: inputStyle, +}; diff --git a/src/wxcomponents/vant-weapp/field/index.wxss b/src/wxcomponents/vant-weapp/field/index.wxss new file mode 100755 index 0000000..5f7d306 --- /dev/null +++ b/src/wxcomponents/vant-weapp/field/index.wxss @@ -0,0 +1 @@ +@import '../common/index.wxss';.van-field{--cell-icon-size:var(--field-icon-size,16px)}.van-field__label{color:var(--field-label-color,#646566)}.van-field__label--disabled{color:var(--field-disabled-text-color,#c8c9cc)}.van-field__body{align-items:center;display:flex}.van-field__body--textarea{box-sizing:border-box;line-height:1.2em;min-height:var(--cell-line-height,24px);padding:3.6px 0}.van-field__control:empty+.van-field__control{display:block}.van-field__control{background-color:initial;border:0;box-sizing:border-box;color:var(--field-input-text-color,#323233);display:none;height:var(--cell-line-height,24px);line-height:inherit;margin:0;min-height:var(--cell-line-height,24px);padding:0;position:relative;resize:none;text-align:left;width:100%}.van-field__control:empty{display:none}.van-field__control--textarea{height:var(--field-text-area-min-height,18px);min-height:var(--field-text-area-min-height,18px)}.van-field__control--error{color:var(--field-input-error-text-color,#ee0a24)}.van-field__control--disabled{background-color:initial;color:var(--field-input-disabled-text-color,#c8c9cc);opacity:1}.van-field__control--center{text-align:center}.van-field__control--right{text-align:right}.van-field__control--custom{align-items:center;display:flex;min-height:var(--cell-line-height,24px)}.van-field__placeholder{color:var(--field-placeholder-text-color,#c8c9cc);left:0;pointer-events:none;position:absolute;right:0;top:0}.van-field__placeholder--error{color:var(--field-error-message-color,#ee0a24)}.van-field__icon-root{align-items:center;display:flex;min-height:var(--cell-line-height,24px)}.van-field__clear-root,.van-field__icon-container{line-height:inherit;margin-right:calc(var(--padding-xs, 8px)*-1);padding:0 var(--padding-xs,8px);vertical-align:middle}.van-field__button,.van-field__clear-root,.van-field__icon-container{flex-shrink:0}.van-field__clear-root{color:var(--field-clear-icon-color,#c8c9cc);font-size:var(--field-clear-icon-size,16px)}.van-field__icon-container{color:var(--field-icon-container-color,#969799);font-size:var(--field-icon-size,16px)}.van-field__icon-container:empty{display:none}.van-field__button{padding-left:var(--padding-xs,8px)}.van-field__button:empty{display:none}.van-field__error-message{color:var(--field-error-message-color,#ee0a24);display:block;font-size:var(--field-error-message-text-font-size,12px);text-align:left}.van-field__error-message--center{text-align:center}.van-field__error-message--right{text-align:right}.van-field__word-limit{color:var(--field-word-limit-color,#646566);font-size:var(--field-word-limit-font-size,12px);line-height:var(--field-word-limit-line-height,16px);margin-top:var(--padding-base,4px);text-align:right}.van-field__word-num{display:inline}.van-field__word-num--full{color:var(--field-word-num-full-color,#ee0a24)} \ No newline at end of file diff --git a/src/wxcomponents/vant-weapp/field/input.wxml b/src/wxcomponents/vant-weapp/field/input.wxml new file mode 100755 index 0000000..e39a5ee --- /dev/null +++ b/src/wxcomponents/vant-weapp/field/input.wxml @@ -0,0 +1,29 @@ + diff --git a/src/wxcomponents/vant-weapp/field/props.d.ts b/src/wxcomponents/vant-weapp/field/props.d.ts new file mode 100755 index 0000000..5cd130a --- /dev/null +++ b/src/wxcomponents/vant-weapp/field/props.d.ts @@ -0,0 +1,4 @@ +/// +export declare const commonProps: WechatMiniprogram.Component.PropertyOption; +export declare const inputProps: WechatMiniprogram.Component.PropertyOption; +export declare const textareaProps: WechatMiniprogram.Component.PropertyOption; diff --git a/src/wxcomponents/vant-weapp/field/props.js b/src/wxcomponents/vant-weapp/field/props.js new file mode 100755 index 0000000..ae405b3 --- /dev/null +++ b/src/wxcomponents/vant-weapp/field/props.js @@ -0,0 +1,64 @@ +export const commonProps = { + value: { + type: String, + observer(value) { + if (value !== this.value) { + this.setData({ innerValue: value }); + this.value = value; + } + }, + }, + placeholder: String, + placeholderStyle: String, + placeholderClass: String, + disabled: Boolean, + maxlength: { + type: Number, + value: -1, + }, + cursorSpacing: { + type: Number, + value: 50, + }, + autoFocus: Boolean, + focus: Boolean, + cursor: { + type: Number, + value: -1, + }, + selectionStart: { + type: Number, + value: -1, + }, + selectionEnd: { + type: Number, + value: -1, + }, + adjustPosition: { + type: Boolean, + value: true, + }, + holdKeyboard: Boolean, +}; +export const inputProps = { + type: { + type: String, + value: 'text', + }, + password: Boolean, + confirmType: String, + confirmHold: Boolean, + alwaysEmbed: Boolean, +}; +export const textareaProps = { + autoHeight: Boolean, + fixed: Boolean, + showConfirmBar: { + type: Boolean, + value: true, + }, + disableDefaultPadding: { + type: Boolean, + value: true, + }, +}; diff --git a/src/wxcomponents/vant-weapp/field/textarea.wxml b/src/wxcomponents/vant-weapp/field/textarea.wxml new file mode 100755 index 0000000..d42c184 --- /dev/null +++ b/src/wxcomponents/vant-weapp/field/textarea.wxml @@ -0,0 +1,30 @@ +