diff --git a/README.md b/README.md index 02061536..a9360f17 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,17 @@ **SmartAdmin** 由 **河南·洛阳** [1024创新实验室](https://www.1024lab.net/) 坚持以 **「高质量代码」为核心,「简洁、高效、安全」**的中后台解决方案! -**国内首个满足《网络安全》、《数据安全》、三级等保**, 支持登录限制、支持接口国产加解密、支持数据加解密等一系列安全措施的开源项目。 +**国内满足《网络安全》、《数据安全》、三级等保**, 支持登录限制、支持接口国产加解密、支持数据加解密等一系列安全措施的开源项目。 **我们开源一套漂亮的代码和一套整洁的代码规范**,让大家在这浮躁的代码世界里感受到一股把代码写好的清流!同时又让开发者节省大量的时间,减少加班,快乐工作,保持谦逊,保持学习,**热爱代码,更热爱生活** ### **技术体系** - 前端:Vue3 + Vite5 + Vue-Router + Pinia + Ant Design Vue 4.X -- 移动端:uniapp + uview2.x +- 移动端:uniapp (vue3版本) + uni-ui + (同时支持APP、小程序、H5) - 后端:SpringBoot + Sa Token + Mybatis-plus + 多种数据库 -- 在线预览:[https://preview.smartadmin.vip](https://preview.smartadmin.vip) +- 电脑在线预览:[https://preview.smartadmin.vip](https://preview.smartadmin.vip) - 官方文档:[https://smartadmin.vip](https://smartadmin.vip) +- 移动端在线预览:[https://app.smartadmin.vip](https://app.smartadmin.vip/#/pages/login/login) ### **理念与思想** - 我们分享的不是徒劳无功的各种功能,而是必须有的功能,如:网络安全、数据变动记录、系统说明文档、版本更新记录、意见反馈、日志、心跳、单号生成器等等。 @@ -74,22 +75,5 @@ -### **联系我们** - -[1024 创新实验室-主任:卓大](https://zhuoda.vip),混迹于各个技术圈,研究过计算机,熟悉点 java,略懂点前端。 -[1024 创新实验室(河南·洛阳)](https://1024lab.net) 致力于成为中原领先、国内一流的技术团队,以技术创新为驱动,合作各类项目(软件外包、技术顾问、培训等等)。 - - - - - - - - - - - - -
加 主任 “卓大” 微信
拉你入群,一起学习
关注 “六边形工程师”
分享:赚钱、代码、生活
请 “1024创新实验室” 喝咖啡
支持我们的开源与分享
diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/interceptor/AdminInterceptor.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/interceptor/AdminInterceptor.java index 6d72d461..1de8e721 100644 --- a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/interceptor/AdminInterceptor.java +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/interceptor/AdminInterceptor.java @@ -109,6 +109,11 @@ public class AdminInterceptor implements HandlerInterceptor { return true; } + // 如果是超级管理员的话,不需要校验权限 + if(requestEmployee.getAdministratorFlag()){ + return true; + } + SaStrategy.instance.checkMethodAnnotation.accept(method); } catch (SaTokenException e) { diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeVO.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeVO.java index 459454fd..dbfcfacc 100644 --- a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeVO.java +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeVO.java @@ -44,11 +44,9 @@ public class NoticeVO { private LocalDateTime publishTime; @Schema(description = "作者") - @NotBlank(message = "作者不能为空") private String author; @Schema(description = "来源") - @NotBlank(message = "标题不能为空") private String source; @Schema(description = "文号") diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/controller/LoginController.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/controller/LoginController.java index 06d940bd..9bf884d5 100644 --- a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/controller/LoginController.java +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/controller/LoginController.java @@ -1,5 +1,6 @@ package net.lab1024.sa.admin.module.system.login.controller; +import cn.dev33.satoken.stp.StpUtil; import cn.hutool.extra.servlet.ServletUtil; import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Operation; @@ -47,7 +48,10 @@ public class LoginController { @GetMapping("/login/getLoginInfo") @Operation(summary = "获取登录结果信息 @author 卓大") public ResponseDTO getLoginInfo() { - return ResponseDTO.ok(loginService.getLoginResult(AdminRequestUtil.getRequestUser())); + LoginResultVO loginResult = loginService.getLoginResult(AdminRequestUtil.getRequestUser()); + String tokenValue = StpUtil.getTokenValue(); + loginResult.setToken(tokenValue); + return ResponseDTO.ok(loginResult); } @Operation(summary = "退出登陆 @author 卓大") diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/domain/PageParam.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/domain/PageParam.java index f9550d87..6e33a4a3 100644 --- a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/domain/PageParam.java +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/domain/PageParam.java @@ -25,12 +25,12 @@ public class PageParam { @Schema(description = "页码(不能为空)", example = "1") @NotNull(message = "分页参数不能为空") - private Integer pageNum; + private Long pageNum; @Schema(description = "每页数量(不能为空)", example = "10") @NotNull(message = "每页数量不能为空") - @Max(value = 200, message = "每页最大为200") - private Integer pageSize; + @Max(value = 500, message = "每页最大为500") + private Long pageSize; @Schema(description = "是否查询总条数") protected Boolean searchCount; diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/domain/ResponseDTO.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/domain/ResponseDTO.java index bb244811..513091a7 100644 --- a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/domain/ResponseDTO.java +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/domain/ResponseDTO.java @@ -24,7 +24,7 @@ public class ResponseDTO { public static final int OK_CODE = 0; - public static final String OK_MSG = "success"; + public static final String OK_MSG = "操作成功"; @Schema(description = "返回码") private Integer code; diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/changelog/controller/ChangeLogController.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/changelog/controller/ChangeLogController.java index 0efaf239..48a60bb7 100644 --- a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/changelog/controller/ChangeLogController.java +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/changelog/controller/ChangeLogController.java @@ -9,9 +9,7 @@ import net.lab1024.sa.base.constant.SwaggerTagConst; import net.lab1024.sa.base.module.support.changelog.domain.form.ChangeLogQueryForm; import net.lab1024.sa.base.module.support.changelog.domain.vo.ChangeLogVO; import net.lab1024.sa.base.module.support.changelog.service.ChangeLogService; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; @@ -36,4 +34,11 @@ public class ChangeLogController extends SupportBaseController { public ResponseDTO> queryPage(@RequestBody @Valid ChangeLogQueryForm queryForm) { return ResponseDTO.ok(changeLogService.queryPage(queryForm)); } + + + @Operation(summary = "变更内容详情 @author 卓大") + @GetMapping("/changeLog/getDetail/{changeLogId}") + public ResponseDTO getDetail(@PathVariable Long changeLogId) { + return ResponseDTO.ok(changeLogService.getById(changeLogId)); + } } \ No newline at end of file diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/changelog/service/ChangeLogService.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/changelog/service/ChangeLogService.java index 26310e56..8823211e 100644 --- a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/changelog/service/ChangeLogService.java +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/changelog/service/ChangeLogService.java @@ -33,7 +33,6 @@ public class ChangeLogService { /** * 分页查询 - * */ public PageResult queryPage(ChangeLogQueryForm queryForm) { Page page = SmartPageUtil.convert2PageQuery(queryForm); @@ -57,7 +56,6 @@ public class ChangeLogService { /** * 更新 - * */ public synchronized ResponseDTO update(ChangeLogUpdateForm updateForm) { ChangeLogEntity existVersion = changeLogDao.selectByVersion(updateForm.getVersion()); @@ -71,7 +69,6 @@ public class ChangeLogService { /** * 批量删除 - * */ public synchronized ResponseDTO batchDelete(List idList) { if (CollectionUtils.isEmpty(idList)) { @@ -93,4 +90,8 @@ public class ChangeLogService { changeLogDao.deleteById(changeLogId); return ResponseDTO.ok(); } + + public ChangeLogVO getById(Long changeLogId) { + return SmartBeanUtil.copy(changeLogDao.selectById(changeLogId), ChangeLogVO.class); + } } diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/controller/CodeGeneratorController.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/controller/CodeGeneratorController.java index 44cb0e20..c72f6904 100644 --- a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/controller/CodeGeneratorController.java +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/codegenerator/controller/CodeGeneratorController.java @@ -87,7 +87,7 @@ public class CodeGeneratorController extends SupportBaseController { ResponseDTO download = codeGeneratorService.download(tableName); if (download.getOk()) { - SmartResponseUtil.setDownloadFileHeader(response, tableName + "-code.zip", (long) download.getData().length); + SmartResponseUtil.setDownloadFileHeader(response, tableName + "_code.zip", (long) download.getData().length); response.getOutputStream().write(download.getData()); } else { SmartResponseUtil.write(response, download); diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/RepeatSubmitAspect.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/RepeatSubmitAspect.java index 55ac6f2c..465460c0 100644 --- a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/RepeatSubmitAspect.java +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/repeatsubmit/RepeatSubmitAspect.java @@ -55,24 +55,15 @@ public class RepeatSubmitAspect { if (StringUtils.isEmpty(ticket)) { return point.proceed(); } - Long timeStamp = this.repeatSubmitTicket.getTicketTimestamp(ticket); - if (timeStamp != null) { + Long lastRequestTime = this.repeatSubmitTicket.getTicketTimestamp(ticket); + if (lastRequestTime != null) { Method method = ((MethodSignature) point.getSignature()).getMethod(); RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); - - // 说明注解去掉了 - if (annotation == null) { - return point.proceed(); - } - int interval = Math.min(annotation.value(), RepeatSubmit.MAX_INTERVAL); - if (System.currentTimeMillis() < timeStamp + interval) { - // 续上时间 能在间隔时间内反复提示用户提交频繁 - this.repeatSubmitTicket.putTicket(ticket); + if (System.currentTimeMillis() < lastRequestTime + interval) { // 提交频繁 return ResponseDTO.error(UserErrorCode.REPEAT_SUBMIT); } - } Object obj = null; try { diff --git a/smart-admin-api/sa-base/src/main/resources/code-generator-template/java/service/Service.java.vm b/smart-admin-api/sa-base/src/main/resources/code-generator-template/java/service/Service.java.vm index 77c40338..923e6e06 100644 --- a/smart-admin-api/sa-base/src/main/resources/code-generator-template/java/service/Service.java.vm +++ b/smart-admin-api/sa-base/src/main/resources/code-generator-template/java/service/Service.java.vm @@ -9,6 +9,7 @@ import net.lab1024.sa.base.common.domain.ResponseDTO; import net.lab1024.sa.base.common.domain.PageResult; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; import javax.annotation.Resource; diff --git a/smart-admin-api/sa-base/src/main/resources/dev/sa-base.yaml b/smart-admin-api/sa-base/src/main/resources/dev/sa-base.yaml index 53767a68..b563a4d1 100644 --- a/smart-admin-api/sa-base/src/main/resources/dev/sa-base.yaml +++ b/smart-admin-api/sa-base/src/main/resources/dev/sa-base.yaml @@ -62,25 +62,9 @@ server: basedir: ${project.log-directory}/tomcat-logs accesslog: enabled: true + max-days: 7 pattern: "%t %{X-Forwarded-For}i %a %r %s (%D ms) %I (%B byte)" - -# 文件上传 配置 -#file: -# storage: -# mode: local -# local: -# upload-path: /home/smart_admin_v3/upload/ #文件上传目录 -# url-prefix: -# cloud: -# region: oss-cn-qingdao -# endpoint: oss-cn-qingdao.aliyuncs.com -# bucket-name: common -# access-key: -# secret-key: -# url-prefix: https://${file.storage.cloud.bucket-name}.${file.storage.cloud.endpoint}/ -# private-url-expire-seconds: 3600 - # 文件上传 配置 file: storage: @@ -108,7 +92,7 @@ springdoc: knife4j: enable: true basic: - enable: true + enable: false username: api # Basic认证用户名 password: 1024 # Basic认证密码 diff --git a/smart-admin-api/sa-base/src/main/resources/pre/sa-base.yaml b/smart-admin-api/sa-base/src/main/resources/pre/sa-base.yaml index 4542a65f..ee6cb459 100644 --- a/smart-admin-api/sa-base/src/main/resources/pre/sa-base.yaml +++ b/smart-admin-api/sa-base/src/main/resources/pre/sa-base.yaml @@ -62,6 +62,7 @@ server: basedir: ${project.log-directory}/tomcat-logs accesslog: enabled: true + max-days: 7 pattern: "%t %{X-Forwarded-For}i %a %r %s (%D ms) %I (%B byte)" diff --git a/smart-admin-api/sa-base/src/main/resources/prod/sa-base.yaml b/smart-admin-api/sa-base/src/main/resources/prod/sa-base.yaml index 811a2982..3307563c 100644 --- a/smart-admin-api/sa-base/src/main/resources/prod/sa-base.yaml +++ b/smart-admin-api/sa-base/src/main/resources/prod/sa-base.yaml @@ -62,6 +62,7 @@ server: basedir: ${project.log-directory}/tomcat-logs accesslog: enabled: true + max-days: 30 pattern: "%t %{X-Forwarded-For}i %a %r %s (%D ms) %I (%B byte)" diff --git a/smart-admin-api/sa-base/src/main/resources/test/sa-base.yaml b/smart-admin-api/sa-base/src/main/resources/test/sa-base.yaml index a3c1008b..9021ea9b 100644 --- a/smart-admin-api/sa-base/src/main/resources/test/sa-base.yaml +++ b/smart-admin-api/sa-base/src/main/resources/test/sa-base.yaml @@ -62,6 +62,7 @@ server: basedir: ${project.log-directory}/tomcat-logs accesslog: enabled: true + max-days: 7 pattern: "%t %{X-Forwarded-For}i %a %r %s (%D ms) %I (%B byte)" diff --git a/smart-admin-web/javascript-ant-design-vue3/src/views/support/change-log/change-log-modal.vue b/smart-admin-web/javascript-ant-design-vue3/src/views/support/change-log/change-log-modal.vue index 477c20eb..5cab7677 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/views/support/change-log/change-log-modal.vue +++ b/smart-admin-web/javascript-ant-design-vue3/src/views/support/change-log/change-log-modal.vue @@ -6,11 +6,12 @@ * @Copyright 1024创新实验室 --> + + + + + +
+ + + diff --git a/smart-app/package.json b/smart-app/package.json new file mode 100644 index 00000000..65d52644 --- /dev/null +++ b/smart-app/package.json @@ -0,0 +1,89 @@ +{ + "name": "smart-app", + "version": "3.0.0", + "author": { + "name": "1024创新实验室(1024lab)", + "email": "lab1024@163.com", + "url": "https://www.1024lab.net" + }, + "license": "MIT", + "homepage": "https://smartadmin.1024lab.net", + "scripts": { + "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:mp-weixin": "uni -p mp-weixin", + "dev:mp-xhs": "uni -p mp-xhs", + "dev:quickapp-webview": "uni -p quickapp-webview", + "dev:quickapp-webview-huawei": "uni -p quickapp-webview-huawei", + "dev:quickapp-webview-union": "uni -p quickapp-webview-union", + "build: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:mp-xhs": "uni build -p mp-xhs", + "build:quickapp-webview": "uni build -p quickapp-webview", + "build:quickapp-webview-huawei": "uni build -p quickapp-webview-huawei", + "build:quickapp-webview-union": "uni build -p quickapp-webview-union" + }, + "dependencies": { + "@dcloudio/uni-app": "3.0.0-3090920231225001", + "@dcloudio/uni-app-plus": "3.0.0-3090920231225001", + "@dcloudio/uni-components": "3.0.0-3090920231225001", + "@dcloudio/uni-h5": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-alipay": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-baidu": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-jd": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-kuaishou": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-lark": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-qq": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-toutiao": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-weixin": "3.0.0-3090920231225001", + "@dcloudio/uni-mp-xhs": "3.0.0-3090920231225001", + "@dcloudio/uni-quickapp-webview": "3.0.0-3090920231225001", + "@dcloudio/uni-ui": "1.5.0", + "crypto-js": "4.1.1", + "dayjs": "1.11.10", + "lodash": "4.17.21", + "pinia": "2.0.36", + "sm-crypto": "0.3.13", + "vue": "3.2.47", + "vue-i18n": "9.1.9" + }, + "devDependencies": { + "@dcloudio/types": "3.3.2", + "@dcloudio/uni-automator": "3.0.0-3090920231225001", + "@dcloudio/uni-cli-shared": "3.0.0-3090920231225001", + "@dcloudio/uni-stacktracey": "3.0.0-3090920231225001", + "@dcloudio/vite-plugin-uni": "3.0.0-3090920231225001", + "@vue/runtime-core": "3.2.45", + "eslint": "8.16.0", + "eslint-config-prettier": "9.0.0", + "eslint-plugin-prettier": "5.0.0", + "eslint-plugin-vue": "9.17.0", + "prettier": "3.0.2", + "sass": "1.69.7", + "sass-loader": "10.1.1", + "vite": "4.0.3" + } +} diff --git a/smart-app/shims-uni.d.ts b/smart-app/shims-uni.d.ts new file mode 100644 index 00000000..ed4adcfc --- /dev/null +++ b/smart-app/shims-uni.d.ts @@ -0,0 +1,10 @@ +/// +import 'vue' + +declare module '@vue/runtime-core' { + type Hooks = App.AppInstance & Page.PageInstance; + + interface ComponentCustomOptions extends Hooks { + + } +} diff --git a/smart-app/src/App.vue b/smart-app/src/App.vue new file mode 100644 index 00000000..8eabb0b9 --- /dev/null +++ b/smart-app/src/App.vue @@ -0,0 +1,22 @@ + + + diff --git a/smart-app/src/api/business/goods/goods-api.js b/smart-app/src/api/business/goods/goods-api.js new file mode 100644 index 00000000..02d132b1 --- /dev/null +++ b/smart-app/src/api/business/goods/goods-api.js @@ -0,0 +1,31 @@ +/* + * @Description: + * @Author: zhuoda + * @Date: 2021-11-05 + * @LastEditTime: 2022-06-23 + * @LastEditors: zhuoda + */ +import { postRequest, getRequest } from '/@/lib/smart-request'; + +export const goodsApi = { + // 添加商品 @author zhuoda + addGoods: (param) => { + return postRequest('/goods/add', param); + }, + // 删除 @author zhuoda + deleteGoods: (goodsId) => { + return getRequest(`/goods/delete/${goodsId}`); + }, + // 批量 @author zhuoda + batchDelete: (goodsIdList) => { + return postRequest('/goods/batchDelete', goodsIdList); + }, + // 分页查询 @author zhuoda + queryGoodsList: (param) => { + return postRequest('/goods/query', param); + }, + // 更新商品 @author zhuoda + updateGoods: (param) => { + return postRequest('/goods/update', param); + }, +}; diff --git a/smart-app/src/api/business/oa/enterprise-api.js b/smart-app/src/api/business/oa/enterprise-api.js new file mode 100644 index 00000000..87cb85af --- /dev/null +++ b/smart-app/src/api/business/oa/enterprise-api.js @@ -0,0 +1,37 @@ +/* + * 企业信息 + * + * @Author: 开云 + * @Date: 2023-09-03 21:47:28 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ +import { postRequest, getRequest } from '/@/lib/smart-request'; + +export const enterpriseApi = { + // 新建企业 @author 开云 + create: (param) => { + return postRequest('/oa/enterprise/create', param); + }, + + // 查询企业详情 @author 开云 + detail: (enterpriseId) => { + return getRequest(`/oa/enterprise/get/${enterpriseId}`); + }, + + // 分页查询企业模块 @author 开云 + pageQuery: (param) => { + return postRequest('/oa/enterprise/page/query', param); + }, + + // 编辑企业 @author 开云 + update: (param) => { + return postRequest('/oa/enterprise/update', param); + }, + + // 删除企业 @author 开云 + delete: (enterpriseId) => { + return getRequest(`/oa/enterprise/delete/${enterpriseId}`); + }, +}; diff --git a/smart-app/src/api/business/oa/notice-api.js b/smart-app/src/api/business/oa/notice-api.js new file mode 100644 index 00000000..8fcd87b9 --- /dev/null +++ b/smart-app/src/api/business/oa/notice-api.js @@ -0,0 +1,33 @@ +/* + * @Description: 公告信息、企业动态 + * @version: + * @Author: zhuoda + * @Date: 2022-08-16 20:34:36 + */ +import { postRequest, getRequest } from '/@/lib/smart-request'; + +export const noticeApi = { + // ---------------- 通知公告类型 ----------------------- + + // 通知公告类型-获取全部 @author zhuoda + getAllNoticeTypeList() { + return getRequest('/oa/noticeType/getAll'); + }, + + // --------------------- 【员工】查看 通知公告 ------------------------- + + // 通知公告-员工-查看详情 @author zhuoda + view(noticeId) { + return getRequest(`/oa/notice/employee/view/${noticeId}`); + }, + + // 通知公告-员工-查询 @author zhuoda + queryEmployeeNotice(param) { + return postRequest('/oa/notice/employee/query', param); + }, + + // 【员工】通知公告-查询 查看记录 @author zhuoda + queryViewRecord(param) { + return postRequest('/oa/notice/employee/queryViewRecord', param); + }, +}; diff --git a/smart-app/src/api/support/change-log-api.js b/smart-app/src/api/support/change-log-api.js new file mode 100644 index 00000000..9fbe1efa --- /dev/null +++ b/smart-app/src/api/support/change-log-api.js @@ -0,0 +1,24 @@ +/** + * 系统更新日志 api 封装 + * + * @Author: 卓大 + * @Date: 2022-09-26 14:53:50 + * @Copyright 1024创新实验室 + */ +import { postRequest, getRequest } from '/@/lib/smart-request'; + +export const changeLogApi = { + /** + * 分页查询 @author 卓大 + */ + queryPage: (param) => { + return postRequest('/support/changeLog/queryPage', param); + }, + + /** + * 详情 @author 卓大 + */ + getDetail: (changeLogId) => { + return getRequest(`/support/changeLog/getDetail/${changeLogId}`); + }, +}; diff --git a/smart-app/src/api/support/dict-api.js b/smart-app/src/api/support/dict-api.js new file mode 100644 index 00000000..70fc7ec2 --- /dev/null +++ b/smart-app/src/api/support/dict-api.js @@ -0,0 +1,59 @@ +/* + * 字典 + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2022-09-03 21:55:25 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ +import { postRequest, getRequest } from '/@/lib/smart-request'; + +export const dictApi = { + // 分页查询数据字典KEY - @author 卓大 + keyQuery: (param) => { + return postRequest('/support/dict/key/query', param); + }, + // 查询全部字典key - @author 卓大 + queryAllKey: () => { + return getRequest('/support/dict/key/queryAll'); + }, + /** + * 分页查询数据字典value - @author 卓大 + */ + valueQuery: (param) => { + return postRequest('/support/dict/value/query', param); + }, + // 数据字典KEY-添加- @author 卓大 + keyAdd: (param) => { + return postRequest('/support/dict/key/add', param); + }, + // 分页查询数据字典value - @author 卓大 + valueAdd: (param) => { + return postRequest('/support/dict/value/add', param); + }, + // 数据字典key-更新- @author 卓大 + keyEdit: (param) => { + return postRequest('/support/dict/key/edit', param); + }, + // 数据字典Value-更新- @author 卓大 + valueEdit: (param) => { + return postRequest('/support/dict/value/edit', param); + }, + // 数据字典key-删除- @author 卓大 + keyDelete: (keyIdList) => { + return postRequest('/support/dict/key/delete', keyIdList); + }, + // 数据字典Value-删除- @author 卓大 + valueDelete: (valueIdList) => { + return postRequest('/support/dict/value/delete', valueIdList); + }, + // 缓存刷新- @author 卓大 + cacheRefresh: () => { + return getRequest('/support/dict/cache/refresh'); + }, + // 数据字典-值列表- @author 卓大 + valueList: (keyCode) => { + return getRequest(`/support/dict/value/list/${keyCode}`); + }, +}; diff --git a/smart-app/src/api/support/feedback-api.js b/smart-app/src/api/support/feedback-api.js new file mode 100644 index 00000000..21cf1c38 --- /dev/null +++ b/smart-app/src/api/support/feedback-api.js @@ -0,0 +1,17 @@ +/* + * 意见反馈 + * + * @Author: 1024创新实验室:开云 + * @Date: 2022-09-03 21:56:31 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ +import { postRequest } from '/src/lib/smart-request'; + +export const feedbackApi = { + // 意见反馈-新增 + addFeedback: (params) => { + return postRequest('/support/feedback/add', params); + }, +}; diff --git a/smart-app/src/api/support/file-api.js b/smart-app/src/api/support/file-api.js new file mode 100644 index 00000000..da822683 --- /dev/null +++ b/smart-app/src/api/support/file-api.js @@ -0,0 +1,14 @@ +/** + * 系统更新日志 api 封装 + * + * @Author: 卓大 + * @Date: 2022-09-26 14:53:50 + * @Copyright 1024创新实验室 + */ +import { uploadRequest } from '/@/lib/smart-request'; + +export const fileApi = { + upload: (file, folder) => { + return uploadRequest(file, folder); + }, +}; diff --git a/smart-app/src/api/system/login-api.js b/smart-app/src/api/system/login-api.js new file mode 100644 index 00000000..bbc2ba40 --- /dev/null +++ b/smart-app/src/api/system/login-api.js @@ -0,0 +1,40 @@ +/* + * 登录 + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2022-09-03 21:59:58 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ +import { getRequest, postRequest } from '/@/lib/smart-request'; + +export const loginApi = { + /** + * 登录 @author 卓大 + */ + login: (param) => { + return postRequest('/login', param); + }, + + /** + * 退出登录 @author 卓大 + */ + logout: () => { + return getRequest('/login/logout'); + }, + + /** + * 获取验证码 @author 卓大 + */ + getCaptcha: () => { + return getRequest('/login/getCaptcha'); + }, + + /** + * 获取登录信息 @author 卓大 + */ + getLoginInfo: () => { + return getRequest('/login/getLoginInfo'); + }, +}; diff --git a/smart-app/src/components/dict-select/index.vue b/smart-app/src/components/dict-select/index.vue new file mode 100644 index 00000000..6e5b66f0 --- /dev/null +++ b/smart-app/src/components/dict-select/index.vue @@ -0,0 +1,55 @@ + + + + diff --git a/smart-app/src/components/smart-card/index.vue b/smart-app/src/components/smart-card/index.vue new file mode 100644 index 00000000..2596546f --- /dev/null +++ b/smart-app/src/components/smart-card/index.vue @@ -0,0 +1,70 @@ + + + + + \ No newline at end of file diff --git a/smart-app/src/components/smart-detail-tabs/index.vue b/smart-app/src/components/smart-detail-tabs/index.vue new file mode 100644 index 00000000..9bdfc12e --- /dev/null +++ b/smart-app/src/components/smart-detail-tabs/index.vue @@ -0,0 +1,73 @@ + + + + + diff --git a/smart-app/src/components/smart-enum-radio/index.vue b/smart-app/src/components/smart-enum-radio/index.vue new file mode 100644 index 00000000..934f82e2 --- /dev/null +++ b/smart-app/src/components/smart-enum-radio/index.vue @@ -0,0 +1,42 @@ + + + + diff --git a/smart-app/src/components/smart-enum-select/index.vue b/smart-app/src/components/smart-enum-select/index.vue new file mode 100644 index 00000000..a0b5a988 --- /dev/null +++ b/smart-app/src/components/smart-enum-select/index.vue @@ -0,0 +1,49 @@ + + + + diff --git a/smart-app/src/constants/business/erp/goods-const.js b/smart-app/src/constants/business/erp/goods-const.js new file mode 100644 index 00000000..599a62d4 --- /dev/null +++ b/smart-app/src/constants/business/erp/goods-const.js @@ -0,0 +1,26 @@ +/* + * 商品 + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2022-09-03 22:08:10 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ +export const GOODS_STATUS_ENUM = { + APPOINTMENT: { + value: 1, + desc: '预约中', + }, + SELL: { + value: 2, + desc: '售卖中', + }, + SELL_OUT: { + value: 3, + desc: '售罄', + }, +}; +export default { + GOODS_STATUS_ENUM, +}; diff --git a/smart-app/src/constants/business/oa/enterprise-const.js b/smart-app/src/constants/business/oa/enterprise-const.js new file mode 100644 index 00000000..7b8f04fa --- /dev/null +++ b/smart-app/src/constants/business/oa/enterprise-const.js @@ -0,0 +1,24 @@ +/* + * 企业 + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2023-09-03 22:07:27 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ + +export const ENTERPRISE_TYPE_ENUM = { + NORMAL: { + value: 1, + desc: '有限企业', + }, + FOREIGN: { + value: 2, + desc: '外资企业', + }, +}; + +export default { + ENTERPRISE_TYPE_ENUM, +}; diff --git a/smart-app/src/constants/common-const.js b/smart-app/src/constants/common-const.js new file mode 100644 index 00000000..8db06ca2 --- /dev/null +++ b/smart-app/src/constants/common-const.js @@ -0,0 +1,70 @@ +/* + * 通用常量 + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2022-09-06 19:57:29 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ + +export const PAGE_SIZE = 10; + +export const PAGE_SIZE_OPTIONS = ['5', '10', '15', '20', '30', '40', '50', '75', '100', '150', '200', '300', '500']; + +//登录页面名字 +export const PAGE_PATH_LOGIN = '/login'; + +//404页面名字 +export const PAGE_PATH_404 = '/404'; + +export const showTableTotal = function (total) { + return `共${total}条`; +}; + +export const FLAG_NUMBER_ENUM = { + TRUE: { + value: 1, + desc: '是', + }, + FALSE: { + value: 0, + desc: '否', + }, +}; + +export const GENDER_ENUM = { + UNKNOWN: { + value: 0, + desc: '未知', + }, + MAN: { + value: 1, + desc: '男', + }, + WOMAN: { + value: 2, + desc: '女', + }, +}; + +export const USER_TYPE_ENUM = { + ADMIN_EMPLOYEE: { + value: 1, + desc: '员工', + }, + +}; + +export const DATA_TYPE_ENUM = { + NORMAL: { + value: 1, + desc: '普通', + }, + ENCRYPT: { + value: 10, + desc: '加密', + }, + +}; + diff --git a/smart-app/src/constants/index.js b/smart-app/src/constants/index.js new file mode 100644 index 00000000..2fbf42c0 --- /dev/null +++ b/smart-app/src/constants/index.js @@ -0,0 +1,26 @@ +/* + * 所有常量入口 + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2022-09-06 19:58:28 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ +import { FLAG_NUMBER_ENUM, GENDER_ENUM, USER_TYPE_ENUM } from './common-const'; +import loginDevice from './system/login-device-const'; +import enterpriseConst from './business/oa/enterprise-const'; +import goodsConst from './business/erp/goods-const'; +import changeLogConst from './support/change-log-const'; +import fileConst from './support/file-const'; + +export default { + FLAG_NUMBER_ENUM, + GENDER_ENUM, + USER_TYPE_ENUM, + ...loginDevice, + ...enterpriseConst, + ...goodsConst, + ...changeLogConst, + ...fileConst, +}; diff --git a/smart-app/src/constants/local-storage-key-const.js b/smart-app/src/constants/local-storage-key-const.js new file mode 100644 index 00000000..8e13a29b --- /dev/null +++ b/smart-app/src/constants/local-storage-key-const.js @@ -0,0 +1,19 @@ +/* + * key 常量 + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2022-09-06 19:58:50 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ + +/** + * key前缀 + */ +const KEY_PREFIX = 'smart_h5_'; +/** + * localStorageKey集合 + */ +// token +export const USER_TOKEN = `${KEY_PREFIX}token`; diff --git a/smart-app/src/constants/regular-const.js b/smart-app/src/constants/regular-const.js new file mode 100644 index 00000000..0633dc87 --- /dev/null +++ b/smart-app/src/constants/regular-const.js @@ -0,0 +1,28 @@ +/* + * 正则常量 + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2022-09-06 19:59:05 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ +export const regular = { + phone: /^(13|14|15|16|17|18|19)\d{9}$/, + qq: /^[1-9]\d{3,}$/, + linkUrl: + /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/, + // eslint-disable-next-line no-useless-escape + isNumber: /(^[\-1-9][1-9]*(.[1-9]+)?)$/, // 判断是否为数字,除了0 外 + isLandlineOrPhone: /^((0\d{2,3}-\d{7,8})|(1[3584]\d{9}))$/, // 验证 座机 或者手机 + account: /^[a-z0-9]{3,16}$/, // 请输入3-16位(小写字母|数字)的账号 + mobileAccount: /^[a-z0-9]{6,16}$/, // 请输入6-16位(小写字母|数字)的账号(和移动端保持一致) + accountDesc: '请输入3-16位(小写字母|数字)的账号', + pwd: /^[A-Za-z0-9._]{6,16}$/, // 请输入6-16位(大小写字母|数字|小数点|下划线)的密码 + pwdDesc: '请输入6-16位(大小写字母|数字|小数点|下划线)的密码', + delBlankSpace: /\s+/g, // 删除空格 + isPdfReg: new RegExp(/\.(pdf|PDF)/), + isElseFileReg: new RegExp(/\.(doc|docx|xls|xlsx|txt|ppt|pptx|pps|ppxs)/), + isIdentityCard: /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X|x)$/, // 验证身份证号 + isChinese: /^[\u4e00-\u9fa5]+$/gi, // 验证是否汉字 +}; diff --git a/smart-app/src/constants/support/change-log-const.js b/smart-app/src/constants/support/change-log-const.js new file mode 100644 index 00000000..dc10d436 --- /dev/null +++ b/smart-app/src/constants/support/change-log-const.js @@ -0,0 +1,32 @@ +/** + * 系统更新日志 枚举 + * + * @Author: 卓大 + * @Date: 2022-09-26 14:53:50 + * @Copyright 1024创新实验室 + */ + +/** + * 更新类型:[1:特大版本功能更新;2:功能更新;3:bug修复] + */ +export const CHANGE_LOG_TYPE_ENUM = { + MAJOR_UPDATE: { + value: 1, + desc: '重大更新', + type: 'error', + }, + FUNCTION_UPDATE: { + value: 2, + desc: '功能更新', + type: 'primary', + }, + BUG_FIX: { + value: 3, + desc: 'Bug修复', + type: 'warning', + }, +}; + +export default { + CHANGE_LOG_TYPE_ENUM, +}; diff --git a/smart-app/src/constants/support/file-const.js b/smart-app/src/constants/support/file-const.js new file mode 100644 index 00000000..6435b96a --- /dev/null +++ b/smart-app/src/constants/support/file-const.js @@ -0,0 +1,31 @@ +/* + * 文件类型 + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2022-09-03 22:09:10 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ +// 文件上传类型 +export const FILE_FOLDER_TYPE_ENUM = { + COMMON: { + value: 1, + desc: '通用', + }, + NOTICE: { + value: 2, + desc: '公告', + }, + HELP_DOC: { + value: 3, + desc: '帮助中心', + }, + FEEDBACK: { + value: 4, + desc: '意见反馈', + }, +}; +export default { + FILE_FOLDER_TYPE_ENUM, +}; diff --git a/smart-app/src/constants/system/login-device-const.js b/smart-app/src/constants/system/login-device-const.js new file mode 100644 index 00000000..f2031212 --- /dev/null +++ b/smart-app/src/constants/system/login-device-const.js @@ -0,0 +1,31 @@ +/* + * 登录设备 + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2022-09-06 19:56:56 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ +export const LOGIN_DEVICE_ENUM = { + PC: { + value: 1, + desc: '电脑端', + }, + ANDROID: { + value: 2, + desc: '安卓', + }, + APPLE: { + value: 3, + desc: '苹果', + }, + H5: { + value: 3, + desc: 'H5', + }, +}; + +export default { + LOGIN_DEVICE_ENUM, +}; diff --git a/smart-app/src/lib/encrypt.js b/smart-app/src/lib/encrypt.js new file mode 100644 index 00000000..8f2fbeed --- /dev/null +++ b/smart-app/src/lib/encrypt.js @@ -0,0 +1,87 @@ +import CryptoJS from 'crypto-js'; +import CryptoSM from 'sm-crypto'; + +function object2string(data) { + if (typeof data === 'Object') { + return JSON.stringify(data); + } + + let str = JSON.stringify(data); + if (str.startsWith("'") || str.startsWith('"')) { + str = str.substring(1); + } + if (str.endsWith("'") || str.endsWith('"')) { + str = str.substring(0, str.length - 1); + } + return str; +} + +// ----------------------- AES 加密、解密 ----------------------- +const AES_KEY = '1024abcd1024abcd1024abcd1024abcd'; + +const AES = { + encryptData: function (data) { + // AES 加密 并转为 base64 + let utf8Data = CryptoJS.enc.Utf8.parse(object2string(data)); + const key = CryptoJS.enc.Utf8.parse(AES_KEY); + const encrypted = CryptoJS.AES.encrypt(utf8Data, key, { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.Pkcs7, + }); + + return encrypted.toString(); + }, + + decryptData: function (data) { + // 第一步:Base64 解码 + let words = CryptoJS.enc.Base64.parse(data); + + // 第二步:AES 解密 + const key = CryptoJS.enc.Utf8.parse(AES_KEY); + return CryptoJS.AES.decrypt({ ciphertext: words }, key, { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.Pkcs7, + }).toString(CryptoJS.enc.Utf8); + }, +}; + +// ----------------------- 国密SM4算法 加密、解密 ----------------------- +const SM4_KEY = '1024abcd1024abcd1024abcd1024abcd'; + +const SM4 = { + encryptData: function (data) { + // 第一步:SM4 加密 + let encryptData = CryptoSM.sm4.encrypt(object2string(data), SM4_KEY); + // 第二步: Base64 编码 + return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(encryptData)); + }, + + decryptData: function (data) { + // 第一步:Base64 解码 + let words = CryptoJS.enc.Base64.parse(data); + let decode64Str = CryptoJS.enc.Utf8.stringify(words); + + // 第二步:SM4 解密 + return CryptoSM.sm4.decrypt(decode64Str, SM4_KEY); + }, +}; + +// ----------------------- 对外暴露: 加密、解密 ----------------------- + +// 默认使用SM4算法 +const EncryptObject = SM4; +// const EncryptObject = AES; + +/** + * 加密 + */ +export const encryptData = function (data) { + return !data ? null : EncryptObject.encryptData(data); +}; + +/** + * 解密 + */ +export const decryptData = function (data) { + return !data ? null : EncryptObject.decryptData(data); +}; diff --git a/smart-app/src/lib/smart-request.js b/smart-app/src/lib/smart-request.js new file mode 100644 index 00000000..b63ccace --- /dev/null +++ b/smart-app/src/lib/smart-request.js @@ -0,0 +1,128 @@ +/* + * ajax请求 + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2022-09-06 20:46:03 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ +import { USER_TOKEN } from '/@/constants/local-storage-key-const'; +import { DATA_TYPE_ENUM } from '/@/constants/common-const'; +import { decryptData, encryptData } from './encrypt'; +import { useUserStore } from '/@/store/modules/system/user'; + +const baseUrl = import.meta.env.VITE_APP_API_URL; + +function getUserToken() { + let token = uni.getStorageSync(USER_TOKEN); + if (token) { + return token; + } + return ''; +} + +/** + * 处理返回的消息 + */ +function handleResponse(response, resolve, reject) { + // 如果是加密数据 + if (response.data.dataType === DATA_TYPE_ENUM.ENCRYPT.value) { + response.data.encryptData = response.data.data; + let decryptStr = decryptData(response.data.data); + if (decryptStr) { + response.data.data = JSON.parse(decryptStr); + } + } + + const res = response.data; + if (res.code && res.code !== 1) { + // `token` 过期或者账号已在别处登录 + if (res.code === 30007 || res.code === 30008 || res.code === 30012) { + uni.showToast({ + title: res.msg, + icon: 'none', + }); + useUserStore().clearUserLoginInfo(); + uni.navigateTo({ url: '/pages/login/login' }); + } + + uni.showToast({ + title: res.msg, + icon: 'none', + }); + reject(response); + } else { + resolve(res); + } +} + +/** + * 通用请求封装 + */ +export const request = function (url, method, data) { + return new Promise((resolve, reject) => { + uni.request({ + url: baseUrl + url, //拼接请求路径 + data: data, + method: method, + header: { + 'x-access-token': getUserToken(), + }, + success: (response) => { + handleResponse(response, resolve, reject); + }, + fail: (error) => { + reject(error); + }, + }); + }); +}; + +/** + * get请求 + */ +export const getRequest = (url) => { + return request(url, 'GET'); +}; + +/** + * post请求 + */ +export const postRequest = (url, data) => { + return request(url, 'POST', data); +}; + +// ================================= 加密 ================================= + +/** + * 加密请求参数的post请求 + */ +export const postEncryptRequest = (url, data) => { + return request(url, 'POST', { encryptData: encryptData(data) }); +}; + +// ================================= 文件 ================================= + +export const uploadRequest = function (filePath, folder) { + return new Promise((resolve, reject) => { + uni.uploadFile({ + url: baseUrl + '/support/file/upload', + filePath, + header: { + 'x-access-token': getUserToken(), + }, + name: 'file', + formData: { + folder, + }, + success: (response) => { + response.data = JSON.parse(response.data.replace('\uFEFF', '')); + handleResponse(response, resolve, reject); + }, + fail: (error) => { + reject(error); + }, + }); + }); +}; diff --git a/smart-app/src/lib/smart-sentry.js b/smart-app/src/lib/smart-sentry.js new file mode 100644 index 00000000..25427c1c --- /dev/null +++ b/smart-app/src/lib/smart-sentry.js @@ -0,0 +1,22 @@ +/* + * 错误上报sentry + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2024-01-02 20:49:28 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ + +export const smartSentry = { + /** + * sentry 主动上报 + */ + captureError: (error) => { + if (error.config && error.data && error && error.headers && error.request && error.status) { + return; + } + // Sentry.captureException(error); + console.error(error); + }, +}; diff --git a/smart-app/src/lib/smart-support.js b/smart-app/src/lib/smart-support.js new file mode 100644 index 00000000..32cb0855 --- /dev/null +++ b/smart-app/src/lib/smart-support.js @@ -0,0 +1,30 @@ +export const SmartLoading = { + show: function (msg) { + uni.showLoading({ title: msg ? msg : '加载中' }); + }, + + hide: function () { + uni.hideLoading(); + }, +}; + +export const SmartToast = { + success: (message) => { + uni.showToast({ + title: message, + icon: 'success', + }); + }, + error: (message) => { + uni.showToast({ + title: message, + icon: 'error', + }); + }, + toast: (message) => { + uni.showToast({ + title: message, + icon: 'none', + }); + }, +}; diff --git a/smart-app/src/main.js b/smart-app/src/main.js new file mode 100644 index 00000000..5fd642b5 --- /dev/null +++ b/smart-app/src/main.js @@ -0,0 +1,22 @@ +import { createSSRApp } from 'vue'; +import App from './App.vue'; +import { store } from './store/index'; + +/*每个页面公共css */ +import './theme/index.scss'; + +// 枚举管理 +import smartEnumPlugin from '/@/plugins/smart-enums-plugin'; +import constantsInfo from '/@/constants/index'; +import lodash from 'lodash'; + +export function createApp() { + const app = createSSRApp(App); + app.use(store); + app.use(smartEnumPlugin, constantsInfo); + app.config.globalProperties.$lodash = lodash; + return { + app, + store, + }; +} diff --git a/smart-app/src/manifest.json b/smart-app/src/manifest.json new file mode 100644 index 00000000..309b9ec3 --- /dev/null +++ b/smart-app/src/manifest.json @@ -0,0 +1,72 @@ +{ + "name" : "", + "appid" : "", + "description" : "", + "versionName" : "1.0.0", + "versionCode" : "100", + "transformPx" : false, + /* 5+App特有相关 */ + "app-plus" : { + "usingComponents" : true, + "nvueStyleCompiler" : "uni-app", + "compilerVersion" : 3, + "splashscreen" : { + "alwaysShowBeforeRender" : true, + "waiting" : true, + "autoclose" : true, + "delay" : 0 + }, + /* 模块配置 */ + "modules" : {}, + /* 应用发布信息 */ + "distribute" : { + /* android打包配置 */ + "android" : { + "permissions" : [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + /* ios打包配置 */ + "ios" : {}, + /* SDK配置 */ + "sdkConfigs" : {} + } + }, + /* 快应用特有相关 */ + "quickapp" : {}, + /* 小程序特有相关 */ + "mp-weixin" : { + "appid" : "", + "setting" : { + "urlCheck" : false + }, + "usingComponents" : true + }, + "mp-alipay" : { + "usingComponents" : true + }, + "mp-baidu" : { + "usingComponents" : true + }, + "mp-toutiao" : { + "usingComponents" : true + }, + "uniStatistics": { + "enable": false + }, + "vueVersion" : "3" +} diff --git a/smart-app/src/pages.json b/smart-app/src/pages.json new file mode 100644 index 00000000..0f8a2c79 --- /dev/null +++ b/smart-app/src/pages.json @@ -0,0 +1,212 @@ +{ + "easycom": { + "autoscan": true, + "custom": { + "^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue", + "^y-(.*)": "@/uni_modules/y-$1/components/y-$1.vue" + } + }, + "pages": [ + { + "path": "pages/home/index", + "style": { + "navigationStyle":"custom", + "navigationBarTitleText": "首页" + } + }, + { + "path": "pages/login/login", + "style": { + "navigationBarTitleText": "登录", + "navigationBarTextStyle": "white", + "navigationStyle": "custom" + } + }, + { + "path" : "pages/mine/mine", + "style" : + { + "navigationBarTitleText" : "我的", + "enablePullDownRefresh" : false, + "navigationStyle": "custom" + } + }, + { + "path" : "pages/enterprise/enterprise-list", + "style" : + { + "navigationBarTitleText" : "客户线索", + "enablePullDownRefresh" : false, + "navigationBarBackgroundColor": "#fff" + } + }, + { + "path" : "pages/enterprise/enterprise-form", + "style" : + { + "navigationBarTitleText" : "添加客户", + "enablePullDownRefresh" : false, + "navigationBarBackgroundColor": "#fff" + } + }, + { + "path" : "pages/enterprise/enterprise-detail", + "style" : + { + "navigationBarTitleText" : "客户详情", + "enablePullDownRefresh" : false, + "navigationBarBackgroundColor": "#fff" + } + }, + { + "path" : "pages/notice/notice-index", + "style" : + { + "navigationBarTitleText" : "通知公告", + "enablePullDownRefresh" : false, + "navigationBarBackgroundColor": "#fff" + } + }, + { + "path" : "pages/notice/notice-detail", + "style" : + { + "navigationBarTitleText" : "公告内容", + "enablePullDownRefresh" : false, + "navigationBarBackgroundColor": "#fff" + } + }, + { + "path" : "pages/goods/goods-index", + "style" : + { + "navigationBarTitleText" : "商品", + "enablePullDownRefresh" : false, + "navigationBarBackgroundColor": "#fff" + } + }, + { + "path" : "pages/support/change-log/change-log-list", + "style" : + { + "navigationBarTitleText" : "版本更新", + "enablePullDownRefresh" : false, + "navigationBarBackgroundColor": "#fff" + } + }, + { + "path" : "pages/support/change-log/change-log-detail", + "style" : + { + "navigationBarTitleText" : "版本更新内容", + "enablePullDownRefresh" : false, + "navigationBarBackgroundColor": "#fff" + } + }, + { + "path" : "pages/message/message", + "style" : + { + "navigationBarTitleText" : "消息", + "enablePullDownRefresh" : false, + "navigationBarBackgroundColor": "#fff" + } + }, + { + "path" : "pages/form/form", + "style" : + { + "navigationBarTitleText" : "提交表单", + "enablePullDownRefresh" : false, + "navigationBarBackgroundColor": "#fff" + } + }, + { + "path" : "pages/select-people/select-people", + "style" : + { + "navigationBarTitleText" : "选择人员", + "enablePullDownRefresh" : false, + "navigationBarBackgroundColor": "#fff" + } + }, + { + "path" : "pages/list/list", + "style" : + { + "navigationBarTitleText" : "常见列表样式1", + "enablePullDownRefresh" : false, + "navigationBarBackgroundColor": "#fff" + } + }, + { + "path" : "pages/list2/list", + "style" : + { + "navigationBarTitleText" : "常见列表样式2", + "enablePullDownRefresh" : false, + "navigationBarBackgroundColor": "#fff" + } + }, + { + "path" : "pages/order-detail/order-detail", + "style" : + { + "navigationBarTitleText" : "运单详情", + "enablePullDownRefresh" : false, + "navigationBarBackgroundColor": "#fff" + } + }, + { + "path" : "pages/support/feedback/feedback-form", + "style" : + { + "navigationBarTitleText" : "意见反馈", + "enablePullDownRefresh" : false, + "navigationBarBackgroundColor": "#fff" + } + } + ], + "globalStyle": { + "navigationBarTextStyle": "black", + "navigationBarTitleText": "uni-app", + "navigationBarBackgroundColor": "#F8F8F8", + "backgroundColor": "#F8F8F8" + }, + "tabBar": { + "color": "#858585", + "selectedColor": "#1A9AFF", + "borderStyle": "black", + "backgroundColor": "#ffffff", + "list": [{ + "pagePath": "pages/home/index", + "iconPath": "static/images/tabbar/home-icon.png", + "selectedIconPath": "static/images/tabbar/home-icon-h.png", + "text": "首页" + }, + { + "pagePath": "pages/list/list", + "iconPath": "static/images/tabbar/list-icon.png", + "selectedIconPath": "static/images/tabbar/list-icon-h.png", + "text": "常见列表1" + }, + { + "pagePath": "pages/list2/list", + "iconPath": "static/images/tabbar/list-icon.png", + "selectedIconPath": "static/images/tabbar/list-icon-h.png", + "text": "常见列表2" + }, + { + "pagePath": "pages/message/message", + "iconPath": "static/images/tabbar/message-icon.png", + "selectedIconPath": "static/images/tabbar/message-icon-h.png", + "text": "消息" + }, + { + "pagePath": "pages/mine/mine", + "iconPath": "static/images/tabbar/mine-icon.png", + "selectedIconPath": "static/images/tabbar/mine-icon-h.png", + "text": "我的" + }] + } +} diff --git a/smart-app/src/pages/enterprise/enterprise-detail.vue b/smart-app/src/pages/enterprise/enterprise-detail.vue new file mode 100644 index 00000000..7f8304f8 --- /dev/null +++ b/smart-app/src/pages/enterprise/enterprise-detail.vue @@ -0,0 +1,245 @@ + + + + + diff --git a/smart-app/src/pages/enterprise/enterprise-form.vue b/smart-app/src/pages/enterprise/enterprise-form.vue new file mode 100644 index 00000000..32d719af --- /dev/null +++ b/smart-app/src/pages/enterprise/enterprise-form.vue @@ -0,0 +1,184 @@ + + + + + diff --git a/smart-app/src/pages/enterprise/enterprise-list.vue b/smart-app/src/pages/enterprise/enterprise-list.vue new file mode 100644 index 00000000..440ac1ae --- /dev/null +++ b/smart-app/src/pages/enterprise/enterprise-list.vue @@ -0,0 +1,217 @@ + + + + + diff --git a/smart-app/src/pages/form/form.vue b/smart-app/src/pages/form/form.vue new file mode 100644 index 00000000..816d1d54 --- /dev/null +++ b/smart-app/src/pages/form/form.vue @@ -0,0 +1,94 @@ + + + + + diff --git a/smart-app/src/pages/goods/components/goods-list.vue b/smart-app/src/pages/goods/components/goods-list.vue new file mode 100644 index 00000000..40c5ca2c --- /dev/null +++ b/smart-app/src/pages/goods/components/goods-list.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/smart-app/src/pages/goods/components/goods-query-form-popup.vue b/smart-app/src/pages/goods/components/goods-query-form-popup.vue new file mode 100644 index 00000000..1290b2b3 --- /dev/null +++ b/smart-app/src/pages/goods/components/goods-query-form-popup.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/smart-app/src/pages/goods/goods-index.vue b/smart-app/src/pages/goods/goods-index.vue new file mode 100644 index 00000000..7d49e85b --- /dev/null +++ b/smart-app/src/pages/goods/goods-index.vue @@ -0,0 +1,222 @@ + + + + + diff --git a/smart-app/src/pages/home/components/banner.vue b/smart-app/src/pages/home/components/banner.vue new file mode 100644 index 00000000..4ef34b58 --- /dev/null +++ b/smart-app/src/pages/home/components/banner.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/smart-app/src/pages/home/components/goods.vue b/smart-app/src/pages/home/components/goods.vue new file mode 100644 index 00000000..abff014f --- /dev/null +++ b/smart-app/src/pages/home/components/goods.vue @@ -0,0 +1,135 @@ + + + + + diff --git a/smart-app/src/pages/home/components/menu.vue b/smart-app/src/pages/home/components/menu.vue new file mode 100644 index 00000000..cb55fa9a --- /dev/null +++ b/smart-app/src/pages/home/components/menu.vue @@ -0,0 +1,131 @@ + + + + + diff --git a/smart-app/src/pages/home/components/notice.vue b/smart-app/src/pages/home/components/notice.vue new file mode 100644 index 00000000..0b82e60a --- /dev/null +++ b/smart-app/src/pages/home/components/notice.vue @@ -0,0 +1,96 @@ + + + + + diff --git a/smart-app/src/pages/home/components/statistics.vue b/smart-app/src/pages/home/components/statistics.vue new file mode 100644 index 00000000..6ee6fe1c --- /dev/null +++ b/smart-app/src/pages/home/components/statistics.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/smart-app/src/pages/home/index.vue b/smart-app/src/pages/home/index.vue new file mode 100644 index 00000000..11b9b1fb --- /dev/null +++ b/smart-app/src/pages/home/index.vue @@ -0,0 +1,80 @@ + + + + + diff --git a/smart-app/src/pages/list/components/list-ui1.vue b/smart-app/src/pages/list/components/list-ui1.vue new file mode 100644 index 00000000..f4c2c694 --- /dev/null +++ b/smart-app/src/pages/list/components/list-ui1.vue @@ -0,0 +1,154 @@ + + + + + diff --git a/smart-app/src/pages/list/components/list-ui2.vue b/smart-app/src/pages/list/components/list-ui2.vue new file mode 100644 index 00000000..badd6521 --- /dev/null +++ b/smart-app/src/pages/list/components/list-ui2.vue @@ -0,0 +1,143 @@ + + + + + diff --git a/smart-app/src/pages/list/components/list-ui3.vue b/smart-app/src/pages/list/components/list-ui3.vue new file mode 100644 index 00000000..4716c832 --- /dev/null +++ b/smart-app/src/pages/list/components/list-ui3.vue @@ -0,0 +1,335 @@ + + + + + diff --git a/smart-app/src/pages/list/components/list-ui4.vue b/smart-app/src/pages/list/components/list-ui4.vue new file mode 100644 index 00000000..84068d2a --- /dev/null +++ b/smart-app/src/pages/list/components/list-ui4.vue @@ -0,0 +1,246 @@ + + + + + diff --git a/smart-app/src/pages/list/list.vue b/smart-app/src/pages/list/list.vue new file mode 100644 index 00000000..a0a788a1 --- /dev/null +++ b/smart-app/src/pages/list/list.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/smart-app/src/pages/list2/components/course-list.vue b/smart-app/src/pages/list2/components/course-list.vue new file mode 100644 index 00000000..407969b7 --- /dev/null +++ b/smart-app/src/pages/list2/components/course-list.vue @@ -0,0 +1,108 @@ + + + + + diff --git a/smart-app/src/pages/list2/components/discount-list.vue b/smart-app/src/pages/list2/components/discount-list.vue new file mode 100644 index 00000000..a923c630 --- /dev/null +++ b/smart-app/src/pages/list2/components/discount-list.vue @@ -0,0 +1,149 @@ + + + + + diff --git a/smart-app/src/pages/list2/components/express-list.vue b/smart-app/src/pages/list2/components/express-list.vue new file mode 100644 index 00000000..e5963b0a --- /dev/null +++ b/smart-app/src/pages/list2/components/express-list.vue @@ -0,0 +1,159 @@ + + + + + diff --git a/smart-app/src/pages/list2/components/iot-list.vue b/smart-app/src/pages/list2/components/iot-list.vue new file mode 100644 index 00000000..20239df7 --- /dev/null +++ b/smart-app/src/pages/list2/components/iot-list.vue @@ -0,0 +1,94 @@ + + + + + diff --git a/smart-app/src/pages/list2/components/service-list.vue b/smart-app/src/pages/list2/components/service-list.vue new file mode 100644 index 00000000..77158bbf --- /dev/null +++ b/smart-app/src/pages/list2/components/service-list.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/smart-app/src/pages/list2/list.vue b/smart-app/src/pages/list2/list.vue new file mode 100644 index 00000000..592a994a --- /dev/null +++ b/smart-app/src/pages/list2/list.vue @@ -0,0 +1,55 @@ + + + + + diff --git a/smart-app/src/pages/login/components/login-check-box.vue b/smart-app/src/pages/login/components/login-check-box.vue new file mode 100644 index 00000000..dc79a678 --- /dev/null +++ b/smart-app/src/pages/login/components/login-check-box.vue @@ -0,0 +1,57 @@ + + + diff --git a/smart-app/src/pages/login/components/other-way-box.vue b/smart-app/src/pages/login/components/other-way-box.vue new file mode 100644 index 00000000..18957ac9 --- /dev/null +++ b/smart-app/src/pages/login/components/other-way-box.vue @@ -0,0 +1,139 @@ + + + diff --git a/smart-app/src/pages/login/login.vue b/smart-app/src/pages/login/login.vue new file mode 100644 index 00000000..19ff67f1 --- /dev/null +++ b/smart-app/src/pages/login/login.vue @@ -0,0 +1,299 @@ + + + diff --git a/smart-app/src/pages/message/message.vue b/smart-app/src/pages/message/message.vue new file mode 100644 index 00000000..b32a4dd2 --- /dev/null +++ b/smart-app/src/pages/message/message.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/smart-app/src/pages/mine/components/mine-menu.vue b/smart-app/src/pages/mine/components/mine-menu.vue new file mode 100644 index 00000000..e046e39f --- /dev/null +++ b/smart-app/src/pages/mine/components/mine-menu.vue @@ -0,0 +1,108 @@ + + + diff --git a/smart-app/src/pages/mine/components/mine-user-blue.vue b/smart-app/src/pages/mine/components/mine-user-blue.vue new file mode 100644 index 00000000..e4549969 --- /dev/null +++ b/smart-app/src/pages/mine/components/mine-user-blue.vue @@ -0,0 +1,111 @@ + + + diff --git a/smart-app/src/pages/mine/components/mine-user-white.vue b/smart-app/src/pages/mine/components/mine-user-white.vue new file mode 100644 index 00000000..8b645e14 --- /dev/null +++ b/smart-app/src/pages/mine/components/mine-user-white.vue @@ -0,0 +1,175 @@ + + + diff --git a/smart-app/src/pages/mine/mine.vue b/smart-app/src/pages/mine/mine.vue new file mode 100644 index 00000000..bed36e89 --- /dev/null +++ b/smart-app/src/pages/mine/mine.vue @@ -0,0 +1,66 @@ + + + diff --git a/smart-app/src/pages/notice/components/notice-list.vue b/smart-app/src/pages/notice/components/notice-list.vue new file mode 100644 index 00000000..83c9275f --- /dev/null +++ b/smart-app/src/pages/notice/components/notice-list.vue @@ -0,0 +1,72 @@ + + + + + diff --git a/smart-app/src/pages/notice/components/notice-query-form-popup.vue b/smart-app/src/pages/notice/components/notice-query-form-popup.vue new file mode 100644 index 00000000..f623bc7b --- /dev/null +++ b/smart-app/src/pages/notice/components/notice-query-form-popup.vue @@ -0,0 +1,115 @@ + + + + + diff --git a/smart-app/src/pages/notice/notice-detail.vue b/smart-app/src/pages/notice/notice-detail.vue new file mode 100644 index 00000000..fd50eb82 --- /dev/null +++ b/smart-app/src/pages/notice/notice-detail.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/smart-app/src/pages/notice/notice-index.vue b/smart-app/src/pages/notice/notice-index.vue new file mode 100644 index 00000000..08521b8c --- /dev/null +++ b/smart-app/src/pages/notice/notice-index.vue @@ -0,0 +1,224 @@ + + + + + diff --git a/smart-app/src/pages/order-detail/components/detail-model-path.vue b/smart-app/src/pages/order-detail/components/detail-model-path.vue new file mode 100644 index 00000000..e0245e05 --- /dev/null +++ b/smart-app/src/pages/order-detail/components/detail-model-path.vue @@ -0,0 +1,118 @@ + + + + + diff --git a/smart-app/src/pages/order-detail/components/order-detail-base-info.vue b/smart-app/src/pages/order-detail/components/order-detail-base-info.vue new file mode 100644 index 00000000..c8702943 --- /dev/null +++ b/smart-app/src/pages/order-detail/components/order-detail-base-info.vue @@ -0,0 +1,32 @@ + + + + + diff --git a/smart-app/src/pages/order-detail/components/order-detail-settle.vue b/smart-app/src/pages/order-detail/components/order-detail-settle.vue new file mode 100644 index 00000000..fe54d9a6 --- /dev/null +++ b/smart-app/src/pages/order-detail/components/order-detail-settle.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/smart-app/src/pages/order-detail/order-detail.vue b/smart-app/src/pages/order-detail/order-detail.vue new file mode 100644 index 00000000..666fd15a --- /dev/null +++ b/smart-app/src/pages/order-detail/order-detail.vue @@ -0,0 +1,52 @@ + + + + + diff --git a/smart-app/src/pages/select-people/select-people.vue b/smart-app/src/pages/select-people/select-people.vue new file mode 100644 index 00000000..d908d385 --- /dev/null +++ b/smart-app/src/pages/select-people/select-people.vue @@ -0,0 +1,143 @@ + + + + + diff --git a/smart-app/src/pages/support/change-log/change-log-detail.vue b/smart-app/src/pages/support/change-log/change-log-detail.vue new file mode 100644 index 00000000..d33314be --- /dev/null +++ b/smart-app/src/pages/support/change-log/change-log-detail.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/smart-app/src/pages/support/change-log/change-log-list.vue b/smart-app/src/pages/support/change-log/change-log-list.vue new file mode 100644 index 00000000..41e2d1b9 --- /dev/null +++ b/smart-app/src/pages/support/change-log/change-log-list.vue @@ -0,0 +1,197 @@ + + + + + diff --git a/smart-app/src/pages/support/feedback/feedback-form.vue b/smart-app/src/pages/support/feedback/feedback-form.vue new file mode 100644 index 00000000..15dd6fd3 --- /dev/null +++ b/smart-app/src/pages/support/feedback/feedback-form.vue @@ -0,0 +1,168 @@ + + + + + diff --git a/smart-app/src/plugins/smart-enums-plugin.js b/smart-app/src/plugins/smart-enums-plugin.js new file mode 100644 index 00000000..0a4e4cc8 --- /dev/null +++ b/smart-app/src/plugins/smart-enums-plugin.js @@ -0,0 +1,97 @@ +/* + * 枚举插件 + * 此插件为 1024创新实验室 自创的插件 + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2022-09-06 20:51:03 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ +import _ from 'lodash'; +import { FLAG_NUMBER_ENUM } from '/@/constants/common-const'; + +export default { + install: (app, smartEnumWrapper) => { + const smartEnumPlugin = {}; + /** + * 根据枚举值获取描述 + * @param {*} constantName 枚举名 + * @param {*} value 枚举值 + * @returns + */ + smartEnumPlugin.getDescByValue = function (constantName, value) { + if (!smartEnumWrapper || !Object.prototype.hasOwnProperty.call(smartEnumWrapper, constantName)) { + return ''; + } + // boolean类型需要做特殊处理 + if (constantName === 'FLAG_NUMBER_ENUM' && !_.isUndefined(value) && typeof value === 'boolean') { + value = value ? FLAG_NUMBER_ENUM.TRUE.value : FLAG_NUMBER_ENUM.FALSE.value; + } + + let smartEnum = smartEnumWrapper[constantName]; + for (let item in smartEnum) { + if (smartEnum[item].value === value) { + return smartEnum[item].desc; + } + } + return ''; + }; + /** + * 根据枚举值获取对象 + * @param {*} constantName 枚举名 + * @param {*} value 枚举值 + * @returns + */ + smartEnumPlugin.getObjectByValue = function (constantName, value) { + if (!smartEnumWrapper || !Object.prototype.hasOwnProperty.call(smartEnumWrapper, constantName)) { + return ''; + } + + let smartEnum = smartEnumWrapper[constantName]; + for (let item in smartEnum) { + if (smartEnum[item].value === value) { + return smartEnum[item]; + } + } + return null; + }; + /** + * 根据枚举名获取对应的描述键值对[{value:desc}] + * @param {*} constantName 枚举名 + * @returns + */ + smartEnumPlugin.getValueDescList = function (constantName) { + if (!Object.prototype.hasOwnProperty.call(smartEnumWrapper, constantName)) { + return []; + } + const result = []; + let targetSmartEnum = smartEnumWrapper[constantName]; + for (let item in targetSmartEnum) { + result.push(targetSmartEnum[item]); + } + return result; + }; + + /** + * 根据枚举名获取对应的value描述键值对{value:desc} + * @param {*} constantName 枚举名 + * @returns + */ + smartEnumPlugin.getValueDesc = function (constantName) { + if (!Object.prototype.hasOwnProperty.call(smartEnumWrapper, constantName)) { + return {}; + } + let smartEnum = smartEnumWrapper[constantName]; + let result = {}; + for (let item in smartEnum) { + let key = smartEnum[item].value + ''; + result[key] = smartEnum[item].desc; + } + return result; + }; + + app.config.globalProperties.$smartEnumPlugin = smartEnumPlugin; + app.provide('smartEnumPlugin', smartEnumPlugin); + }, +}; diff --git a/smart-app/src/shime-uni.d.ts b/smart-app/src/shime-uni.d.ts new file mode 100644 index 00000000..b3d3cc9c --- /dev/null +++ b/smart-app/src/shime-uni.d.ts @@ -0,0 +1,6 @@ +export {}; + +declare module "vue" { + type Hooks = App.AppInstance & Page.PageInstance; + interface ComponentCustomOptions extends Hooks {} +} \ No newline at end of file diff --git a/smart-app/src/static/common/back-icon.png b/smart-app/src/static/common/back-icon.png new file mode 100644 index 00000000..9b82c797 Binary files /dev/null and b/smart-app/src/static/common/back-icon.png differ diff --git a/smart-app/src/static/common/update-app.png b/smart-app/src/static/common/update-app.png new file mode 100644 index 00000000..b122df57 Binary files /dev/null and b/smart-app/src/static/common/update-app.png differ diff --git a/smart-app/src/static/images/form/add-image.png b/smart-app/src/static/images/form/add-image.png new file mode 100644 index 00000000..42959927 Binary files /dev/null and b/smart-app/src/static/images/form/add-image.png differ diff --git a/smart-app/src/static/images/form/add.png b/smart-app/src/static/images/form/add.png new file mode 100644 index 00000000..a71d9328 Binary files /dev/null and b/smart-app/src/static/images/form/add.png differ diff --git a/smart-app/src/static/images/form/back.png b/smart-app/src/static/images/form/back.png new file mode 100644 index 00000000..1c82eb77 Binary files /dev/null and b/smart-app/src/static/images/form/back.png differ diff --git a/smart-app/src/static/images/form/close-image.png b/smart-app/src/static/images/form/close-image.png new file mode 100644 index 00000000..2702be04 Binary files /dev/null and b/smart-app/src/static/images/form/close-image.png differ diff --git a/smart-app/src/static/images/form/submit.png b/smart-app/src/static/images/form/submit.png new file mode 100644 index 00000000..cdc5392a Binary files /dev/null and b/smart-app/src/static/images/form/submit.png differ diff --git a/smart-app/src/static/images/form/title-bg.png b/smart-app/src/static/images/form/title-bg.png new file mode 100644 index 00000000..48613b81 Binary files /dev/null and b/smart-app/src/static/images/form/title-bg.png differ diff --git a/smart-app/src/static/images/home/admin-icon.png b/smart-app/src/static/images/home/admin-icon.png new file mode 100644 index 00000000..1c9e386d Binary files /dev/null and b/smart-app/src/static/images/home/admin-icon.png differ diff --git a/smart-app/src/static/images/home/copy-icon.png b/smart-app/src/static/images/home/copy-icon.png new file mode 100644 index 00000000..319a30c1 Binary files /dev/null and b/smart-app/src/static/images/home/copy-icon.png differ diff --git a/smart-app/src/static/images/home/detail-icon.png b/smart-app/src/static/images/home/detail-icon.png new file mode 100644 index 00000000..845ca3a5 Binary files /dev/null and b/smart-app/src/static/images/home/detail-icon.png differ diff --git a/smart-app/src/static/images/home/download-icon.png b/smart-app/src/static/images/home/download-icon.png new file mode 100644 index 00000000..bb946e07 Binary files /dev/null and b/smart-app/src/static/images/home/download-icon.png differ diff --git a/smart-app/src/static/images/home/link-icon.png b/smart-app/src/static/images/home/link-icon.png new file mode 100644 index 00000000..b32191d6 Binary files /dev/null and b/smart-app/src/static/images/home/link-icon.png differ diff --git a/smart-app/src/static/images/home/qq-icon.png b/smart-app/src/static/images/home/qq-icon.png new file mode 100644 index 00000000..d0627fea Binary files /dev/null and b/smart-app/src/static/images/home/qq-icon.png differ diff --git a/smart-app/src/static/images/home/refresh-icon.png b/smart-app/src/static/images/home/refresh-icon.png new file mode 100644 index 00000000..fc10efa4 Binary files /dev/null and b/smart-app/src/static/images/home/refresh-icon.png differ diff --git a/smart-app/src/static/images/home/round-icon.png b/smart-app/src/static/images/home/round-icon.png new file mode 100644 index 00000000..a073b5d6 Binary files /dev/null and b/smart-app/src/static/images/home/round-icon.png differ diff --git a/smart-app/src/static/images/home/search-clear.png b/smart-app/src/static/images/home/search-clear.png new file mode 100644 index 00000000..2e8c4248 Binary files /dev/null and b/smart-app/src/static/images/home/search-clear.png differ diff --git a/smart-app/src/static/images/home/search-icon.png b/smart-app/src/static/images/home/search-icon.png new file mode 100644 index 00000000..1e06edbc Binary files /dev/null and b/smart-app/src/static/images/home/search-icon.png differ diff --git a/smart-app/src/static/images/home/search.png b/smart-app/src/static/images/home/search.png new file mode 100644 index 00000000..56ec0fd6 Binary files /dev/null and b/smart-app/src/static/images/home/search.png differ diff --git a/smart-app/src/static/images/home/share-icon.png b/smart-app/src/static/images/home/share-icon.png new file mode 100644 index 00000000..dbd763e9 Binary files /dev/null and b/smart-app/src/static/images/home/share-icon.png differ diff --git a/smart-app/src/static/images/home/vip-module-background.png b/smart-app/src/static/images/home/vip-module-background.png new file mode 100644 index 00000000..d95a8add Binary files /dev/null and b/smart-app/src/static/images/home/vip-module-background.png differ diff --git a/smart-app/src/static/images/home/vip-module-icon.png b/smart-app/src/static/images/home/vip-module-icon.png new file mode 100644 index 00000000..93e225bb Binary files /dev/null and b/smart-app/src/static/images/home/vip-module-icon.png differ diff --git a/smart-app/src/static/images/home/wechat-icon.png b/smart-app/src/static/images/home/wechat-icon.png new file mode 100644 index 00000000..eb19341c Binary files /dev/null and b/smart-app/src/static/images/home/wechat-icon.png differ diff --git a/smart-app/src/static/images/home/wechat-share-icon.png b/smart-app/src/static/images/home/wechat-share-icon.png new file mode 100644 index 00000000..ff96b542 Binary files /dev/null and b/smart-app/src/static/images/home/wechat-share-icon.png differ diff --git a/smart-app/src/static/images/home/weibo-icon.png b/smart-app/src/static/images/home/weibo-icon.png new file mode 100644 index 00000000..c11eb4ea Binary files /dev/null and b/smart-app/src/static/images/home/weibo-icon.png differ diff --git a/smart-app/src/static/images/index/banner.png b/smart-app/src/static/images/index/banner.png new file mode 100644 index 00000000..a82b2186 Binary files /dev/null and b/smart-app/src/static/images/index/banner.png differ diff --git a/smart-app/src/static/images/index/ic_home_menu1.png b/smart-app/src/static/images/index/ic_home_menu1.png new file mode 100644 index 00000000..49f90bdf Binary files /dev/null and b/smart-app/src/static/images/index/ic_home_menu1.png differ diff --git a/smart-app/src/static/images/index/ic_home_menu10.png b/smart-app/src/static/images/index/ic_home_menu10.png new file mode 100644 index 00000000..2c256ce5 Binary files /dev/null and b/smart-app/src/static/images/index/ic_home_menu10.png differ diff --git a/smart-app/src/static/images/index/ic_home_menu2.png b/smart-app/src/static/images/index/ic_home_menu2.png new file mode 100644 index 00000000..43969741 Binary files /dev/null and b/smart-app/src/static/images/index/ic_home_menu2.png differ diff --git a/smart-app/src/static/images/index/ic_home_menu3.png b/smart-app/src/static/images/index/ic_home_menu3.png new file mode 100644 index 00000000..dfdfcd37 Binary files /dev/null and b/smart-app/src/static/images/index/ic_home_menu3.png differ diff --git a/smart-app/src/static/images/index/ic_home_menu4.png b/smart-app/src/static/images/index/ic_home_menu4.png new file mode 100644 index 00000000..3981aff0 Binary files /dev/null and b/smart-app/src/static/images/index/ic_home_menu4.png differ diff --git a/smart-app/src/static/images/index/ic_home_menu5.png b/smart-app/src/static/images/index/ic_home_menu5.png new file mode 100644 index 00000000..9cb79f66 Binary files /dev/null and b/smart-app/src/static/images/index/ic_home_menu5.png differ diff --git a/smart-app/src/static/images/index/ic_home_menu6.png b/smart-app/src/static/images/index/ic_home_menu6.png new file mode 100644 index 00000000..8a073a9b Binary files /dev/null and b/smart-app/src/static/images/index/ic_home_menu6.png differ diff --git a/smart-app/src/static/images/index/ic_home_menu7.png b/smart-app/src/static/images/index/ic_home_menu7.png new file mode 100644 index 00000000..ffb513f7 Binary files /dev/null and b/smart-app/src/static/images/index/ic_home_menu7.png differ diff --git a/smart-app/src/static/images/index/ic_home_menu8.png b/smart-app/src/static/images/index/ic_home_menu8.png new file mode 100644 index 00000000..4e6e8faa Binary files /dev/null and b/smart-app/src/static/images/index/ic_home_menu8.png differ diff --git a/smart-app/src/static/images/index/ic_home_menu9.png b/smart-app/src/static/images/index/ic_home_menu9.png new file mode 100644 index 00000000..0dbf339a Binary files /dev/null and b/smart-app/src/static/images/index/ic_home_menu9.png differ diff --git a/smart-app/src/static/images/index/ic_scan.png b/smart-app/src/static/images/index/ic_scan.png new file mode 100644 index 00000000..affbc7aa Binary files /dev/null and b/smart-app/src/static/images/index/ic_scan.png differ diff --git a/smart-app/src/static/images/index/ic_search.png b/smart-app/src/static/images/index/ic_search.png new file mode 100644 index 00000000..eeadc47e Binary files /dev/null and b/smart-app/src/static/images/index/ic_search.png differ diff --git a/smart-app/src/static/images/list/add.png b/smart-app/src/static/images/list/add.png new file mode 100644 index 00000000..0917dc17 Binary files /dev/null and b/smart-app/src/static/images/list/add.png differ diff --git a/smart-app/src/static/images/list/blue.png b/smart-app/src/static/images/list/blue.png new file mode 100644 index 00000000..49743af2 Binary files /dev/null and b/smart-app/src/static/images/list/blue.png differ diff --git a/smart-app/src/static/images/list/camera.png b/smart-app/src/static/images/list/camera.png new file mode 100644 index 00000000..387c740b Binary files /dev/null and b/smart-app/src/static/images/list/camera.png differ diff --git a/smart-app/src/static/images/list/form-list.png b/smart-app/src/static/images/list/form-list.png new file mode 100644 index 00000000..c7611f18 Binary files /dev/null and b/smart-app/src/static/images/list/form-list.png differ diff --git a/smart-app/src/static/images/list/phone.png b/smart-app/src/static/images/list/phone.png new file mode 100644 index 00000000..cb72cf88 Binary files /dev/null and b/smart-app/src/static/images/list/phone.png differ diff --git a/smart-app/src/static/images/list/red.png b/smart-app/src/static/images/list/red.png new file mode 100644 index 00000000..6540fc6a Binary files /dev/null and b/smart-app/src/static/images/list/red.png differ diff --git a/smart-app/src/static/images/list/repair-report.png b/smart-app/src/static/images/list/repair-report.png new file mode 100644 index 00000000..cee2265e Binary files /dev/null and b/smart-app/src/static/images/list/repair-report.png differ diff --git a/smart-app/src/static/images/list/success.png b/smart-app/src/static/images/list/success.png new file mode 100644 index 00000000..f41996ec Binary files /dev/null and b/smart-app/src/static/images/list/success.png differ diff --git a/smart-app/src/static/images/list/use.png b/smart-app/src/static/images/list/use.png new file mode 100644 index 00000000..9d57d11e Binary files /dev/null and b/smart-app/src/static/images/list/use.png differ diff --git a/smart-app/src/static/images/list3/complete-icon.png b/smart-app/src/static/images/list3/complete-icon.png new file mode 100644 index 00000000..b5635fa8 Binary files /dev/null and b/smart-app/src/static/images/list3/complete-icon.png differ diff --git a/smart-app/src/static/images/list3/phone.png b/smart-app/src/static/images/list3/phone.png new file mode 100644 index 00000000..0a5e9f06 Binary files /dev/null and b/smart-app/src/static/images/list3/phone.png differ diff --git a/smart-app/src/static/images/list3/photograph-icon.png b/smart-app/src/static/images/list3/photograph-icon.png new file mode 100644 index 00000000..a3c3f96c Binary files /dev/null and b/smart-app/src/static/images/list3/photograph-icon.png differ diff --git a/smart-app/src/static/images/login/bind-error.png b/smart-app/src/static/images/login/bind-error.png new file mode 100644 index 00000000..db07f383 Binary files /dev/null and b/smart-app/src/static/images/login/bind-error.png differ diff --git a/smart-app/src/static/images/login/bind-success.png b/smart-app/src/static/images/login/bind-success.png new file mode 100644 index 00000000..6ff9c124 Binary files /dev/null and b/smart-app/src/static/images/login/bind-success.png differ diff --git a/smart-app/src/static/images/login/check-in.png b/smart-app/src/static/images/login/check-in.png new file mode 100644 index 00000000..5b318378 Binary files /dev/null and b/smart-app/src/static/images/login/check-in.png differ diff --git a/smart-app/src/static/images/login/check-out.png b/smart-app/src/static/images/login/check-out.png new file mode 100644 index 00000000..17da80c1 Binary files /dev/null and b/smart-app/src/static/images/login/check-out.png differ diff --git a/smart-app/src/static/images/login/ios-login-icon.png b/smart-app/src/static/images/login/ios-login-icon.png new file mode 100644 index 00000000..075df761 Binary files /dev/null and b/smart-app/src/static/images/login/ios-login-icon.png differ diff --git a/smart-app/src/static/images/login/login-logo.png b/smart-app/src/static/images/login/login-logo.png new file mode 100644 index 00000000..a2573383 Binary files /dev/null and b/smart-app/src/static/images/login/login-logo.png differ diff --git a/smart-app/src/static/images/login/login-password.png b/smart-app/src/static/images/login/login-password.png new file mode 100644 index 00000000..8475337b Binary files /dev/null and b/smart-app/src/static/images/login/login-password.png differ diff --git a/smart-app/src/static/images/login/login-top-back.png b/smart-app/src/static/images/login/login-top-back.png new file mode 100644 index 00000000..64e132b4 Binary files /dev/null and b/smart-app/src/static/images/login/login-top-back.png differ diff --git a/smart-app/src/static/images/login/login-username.png b/smart-app/src/static/images/login/login-username.png new file mode 100644 index 00000000..e1e0a457 Binary files /dev/null and b/smart-app/src/static/images/login/login-username.png differ diff --git a/smart-app/src/static/images/login/phone-login-icon.png b/smart-app/src/static/images/login/phone-login-icon.png new file mode 100644 index 00000000..3d22f45c Binary files /dev/null and b/smart-app/src/static/images/login/phone-login-icon.png differ diff --git a/smart-app/src/static/images/login/wx-icon.png b/smart-app/src/static/images/login/wx-icon.png new file mode 100644 index 00000000..0b38afdf Binary files /dev/null and b/smart-app/src/static/images/login/wx-icon.png differ diff --git a/smart-app/src/static/images/login/wx-login-icon.png b/smart-app/src/static/images/login/wx-login-icon.png new file mode 100644 index 00000000..8f86d958 Binary files /dev/null and b/smart-app/src/static/images/login/wx-login-icon.png differ diff --git a/smart-app/src/static/images/message/approve.png b/smart-app/src/static/images/message/approve.png new file mode 100644 index 00000000..b3f10707 Binary files /dev/null and b/smart-app/src/static/images/message/approve.png differ diff --git a/smart-app/src/static/images/message/message.png b/smart-app/src/static/images/message/message.png new file mode 100644 index 00000000..c359f3dc Binary files /dev/null and b/smart-app/src/static/images/message/message.png differ diff --git a/smart-app/src/static/images/mine/arrow.png b/smart-app/src/static/images/mine/arrow.png new file mode 100644 index 00000000..0efd51fe Binary files /dev/null and b/smart-app/src/static/images/mine/arrow.png differ diff --git a/smart-app/src/static/images/mine/common-select-icon.png b/smart-app/src/static/images/mine/common-select-icon.png new file mode 100644 index 00000000..5b318378 Binary files /dev/null and b/smart-app/src/static/images/mine/common-select-icon.png differ diff --git a/smart-app/src/static/images/mine/common-unselect-icon.png b/smart-app/src/static/images/mine/common-unselect-icon.png new file mode 100644 index 00000000..17da80c1 Binary files /dev/null and b/smart-app/src/static/images/mine/common-unselect-icon.png differ diff --git a/smart-app/src/static/images/mine/customer-icon.png b/smart-app/src/static/images/mine/customer-icon.png new file mode 100644 index 00000000..34d7d9ef Binary files /dev/null and b/smart-app/src/static/images/mine/customer-icon.png differ diff --git a/smart-app/src/static/images/mine/logout-icon.png b/smart-app/src/static/images/mine/logout-icon.png new file mode 100644 index 00000000..980da270 Binary files /dev/null and b/smart-app/src/static/images/mine/logout-icon.png differ diff --git a/smart-app/src/static/images/mine/mine-about-us.png b/smart-app/src/static/images/mine/mine-about-us.png new file mode 100644 index 00000000..7a8d349e Binary files /dev/null and b/smart-app/src/static/images/mine/mine-about-us.png differ diff --git a/smart-app/src/static/images/mine/mine-account.png b/smart-app/src/static/images/mine/mine-account.png new file mode 100644 index 00000000..5bc69743 Binary files /dev/null and b/smart-app/src/static/images/mine/mine-account.png differ diff --git a/smart-app/src/static/images/mine/mine-feedback.png b/smart-app/src/static/images/mine/mine-feedback.png new file mode 100644 index 00000000..edbd7246 Binary files /dev/null and b/smart-app/src/static/images/mine/mine-feedback.png differ diff --git a/smart-app/src/static/images/mine/mine-menu-address.png b/smart-app/src/static/images/mine/mine-menu-address.png new file mode 100644 index 00000000..5533ff8b Binary files /dev/null and b/smart-app/src/static/images/mine/mine-menu-address.png differ diff --git a/smart-app/src/static/images/mine/mine-menu-balance.png b/smart-app/src/static/images/mine/mine-menu-balance.png new file mode 100644 index 00000000..99e8e91f Binary files /dev/null and b/smart-app/src/static/images/mine/mine-menu-balance.png differ diff --git a/smart-app/src/static/images/mine/mine-menu-collect.png b/smart-app/src/static/images/mine/mine-menu-collect.png new file mode 100644 index 00000000..e7b75e2c Binary files /dev/null and b/smart-app/src/static/images/mine/mine-menu-collect.png differ diff --git a/smart-app/src/static/images/mine/mine-menu-coupon.png b/smart-app/src/static/images/mine/mine-menu-coupon.png new file mode 100644 index 00000000..a868c635 Binary files /dev/null and b/smart-app/src/static/images/mine/mine-menu-coupon.png differ diff --git a/smart-app/src/static/images/mine/mine-message.png b/smart-app/src/static/images/mine/mine-message.png new file mode 100644 index 00000000..97431b8c Binary files /dev/null and b/smart-app/src/static/images/mine/mine-message.png differ diff --git a/smart-app/src/static/images/mine/mine-protocol.png b/smart-app/src/static/images/mine/mine-protocol.png new file mode 100644 index 00000000..332cb436 Binary files /dev/null and b/smart-app/src/static/images/mine/mine-protocol.png differ diff --git a/smart-app/src/static/images/mine/mine-service.png b/smart-app/src/static/images/mine/mine-service.png new file mode 100644 index 00000000..ad5e9fe6 Binary files /dev/null and b/smart-app/src/static/images/mine/mine-service.png differ diff --git a/smart-app/src/static/images/mine/mine-version-info.png b/smart-app/src/static/images/mine/mine-version-info.png new file mode 100644 index 00000000..77569231 Binary files /dev/null and b/smart-app/src/static/images/mine/mine-version-info.png differ diff --git a/smart-app/src/static/images/mine/no-vip-flag.png b/smart-app/src/static/images/mine/no-vip-flag.png new file mode 100644 index 00000000..9f4691ef Binary files /dev/null and b/smart-app/src/static/images/mine/no-vip-flag.png differ diff --git a/smart-app/src/static/images/mine/open-vip.png b/smart-app/src/static/images/mine/open-vip.png new file mode 100644 index 00000000..1512ef3e Binary files /dev/null and b/smart-app/src/static/images/mine/open-vip.png differ diff --git a/smart-app/src/static/images/mine/phone-icon.png b/smart-app/src/static/images/mine/phone-icon.png new file mode 100644 index 00000000..eb112531 Binary files /dev/null and b/smart-app/src/static/images/mine/phone-icon.png differ diff --git a/smart-app/src/static/images/mine/top-background.png b/smart-app/src/static/images/mine/top-background.png new file mode 100644 index 00000000..2874c07d Binary files /dev/null and b/smart-app/src/static/images/mine/top-background.png differ diff --git a/smart-app/src/static/images/mine/user-agreement-icon.png b/smart-app/src/static/images/mine/user-agreement-icon.png new file mode 100644 index 00000000..b5850dd0 Binary files /dev/null and b/smart-app/src/static/images/mine/user-agreement-icon.png differ diff --git a/smart-app/src/static/images/mine/vip-background.png b/smart-app/src/static/images/mine/vip-background.png new file mode 100644 index 00000000..76871754 Binary files /dev/null and b/smart-app/src/static/images/mine/vip-background.png differ diff --git a/smart-app/src/static/images/mine/vip-bg.png b/smart-app/src/static/images/mine/vip-bg.png new file mode 100644 index 00000000..6258ffee Binary files /dev/null and b/smart-app/src/static/images/mine/vip-bg.png differ diff --git a/smart-app/src/static/images/mine/vip-icon.png b/smart-app/src/static/images/mine/vip-icon.png new file mode 100644 index 00000000..9642d89a Binary files /dev/null and b/smart-app/src/static/images/mine/vip-icon.png differ diff --git a/smart-app/src/static/images/notice/01.png b/smart-app/src/static/images/notice/01.png new file mode 100644 index 00000000..4114bc93 Binary files /dev/null and b/smart-app/src/static/images/notice/01.png differ diff --git a/smart-app/src/static/images/notice/02.png b/smart-app/src/static/images/notice/02.png new file mode 100644 index 00000000..33c1789e Binary files /dev/null and b/smart-app/src/static/images/notice/02.png differ diff --git a/smart-app/src/static/images/pure-list/blue.png b/smart-app/src/static/images/pure-list/blue.png new file mode 100644 index 00000000..44ddfc7c Binary files /dev/null and b/smart-app/src/static/images/pure-list/blue.png differ diff --git a/smart-app/src/static/images/pure-list/employ.png b/smart-app/src/static/images/pure-list/employ.png new file mode 100644 index 00000000..48ed7b33 Binary files /dev/null and b/smart-app/src/static/images/pure-list/employ.png differ diff --git a/smart-app/src/static/images/pure-list/maintain.png b/smart-app/src/static/images/pure-list/maintain.png new file mode 100644 index 00000000..5e5cdba7 Binary files /dev/null and b/smart-app/src/static/images/pure-list/maintain.png differ diff --git a/smart-app/src/static/images/pure-list/obsolete.png b/smart-app/src/static/images/pure-list/obsolete.png new file mode 100644 index 00000000..6ecf5619 Binary files /dev/null and b/smart-app/src/static/images/pure-list/obsolete.png differ diff --git a/smart-app/src/static/images/pure-list/orange.png b/smart-app/src/static/images/pure-list/orange.png new file mode 100644 index 00000000..0e799ed2 Binary files /dev/null and b/smart-app/src/static/images/pure-list/orange.png differ diff --git a/smart-app/src/static/images/pure-list/overdue.png b/smart-app/src/static/images/pure-list/overdue.png new file mode 100644 index 00000000..fa98a9c2 Binary files /dev/null and b/smart-app/src/static/images/pure-list/overdue.png differ diff --git a/smart-app/src/static/images/select-people/select.png b/smart-app/src/static/images/select-people/select.png new file mode 100644 index 00000000..26fb057f Binary files /dev/null and b/smart-app/src/static/images/select-people/select.png differ diff --git a/smart-app/src/static/images/tabbar/home-icon-h.png b/smart-app/src/static/images/tabbar/home-icon-h.png new file mode 100644 index 00000000..b0bcca01 Binary files /dev/null and b/smart-app/src/static/images/tabbar/home-icon-h.png differ diff --git a/smart-app/src/static/images/tabbar/home-icon.png b/smart-app/src/static/images/tabbar/home-icon.png new file mode 100644 index 00000000..a1e93090 Binary files /dev/null and b/smart-app/src/static/images/tabbar/home-icon.png differ diff --git a/smart-app/src/static/images/tabbar/list-icon-h.png b/smart-app/src/static/images/tabbar/list-icon-h.png new file mode 100644 index 00000000..d51fd7e0 Binary files /dev/null and b/smart-app/src/static/images/tabbar/list-icon-h.png differ diff --git a/smart-app/src/static/images/tabbar/list-icon.png b/smart-app/src/static/images/tabbar/list-icon.png new file mode 100644 index 00000000..a2cb0551 Binary files /dev/null and b/smart-app/src/static/images/tabbar/list-icon.png differ diff --git a/smart-app/src/static/images/tabbar/message-icon-h.png b/smart-app/src/static/images/tabbar/message-icon-h.png new file mode 100644 index 00000000..722fd688 Binary files /dev/null and b/smart-app/src/static/images/tabbar/message-icon-h.png differ diff --git a/smart-app/src/static/images/tabbar/message-icon.png b/smart-app/src/static/images/tabbar/message-icon.png new file mode 100644 index 00000000..3936f33f Binary files /dev/null and b/smart-app/src/static/images/tabbar/message-icon.png differ diff --git a/smart-app/src/static/images/tabbar/mine-icon-h.png b/smart-app/src/static/images/tabbar/mine-icon-h.png new file mode 100644 index 00000000..1ed44317 Binary files /dev/null and b/smart-app/src/static/images/tabbar/mine-icon-h.png differ diff --git a/smart-app/src/static/images/tabbar/mine-icon.png b/smart-app/src/static/images/tabbar/mine-icon.png new file mode 100644 index 00000000..7a0f25da Binary files /dev/null and b/smart-app/src/static/images/tabbar/mine-icon.png differ diff --git a/smart-app/src/static/images/uni-modules/uni-mescroll/mescroll-empty.png b/smart-app/src/static/images/uni-modules/uni-mescroll/mescroll-empty.png new file mode 100644 index 00000000..ff333ab4 Binary files /dev/null and b/smart-app/src/static/images/uni-modules/uni-mescroll/mescroll-empty.png differ diff --git a/smart-app/src/static/images/uni-modules/uni-mescroll/mescroll-totop.png b/smart-app/src/static/images/uni-modules/uni-mescroll/mescroll-totop.png new file mode 100644 index 00000000..62534c4d Binary files /dev/null and b/smart-app/src/static/images/uni-modules/uni-mescroll/mescroll-totop.png differ diff --git a/smart-app/src/static/logo.png b/smart-app/src/static/logo.png new file mode 100644 index 00000000..b5771e20 Binary files /dev/null and b/smart-app/src/static/logo.png differ diff --git a/smart-app/src/store/index.js b/smart-app/src/store/index.js new file mode 100644 index 00000000..85042010 --- /dev/null +++ b/smart-app/src/store/index.js @@ -0,0 +1,12 @@ +/* + * pinia 状态管理 + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2022-09-06 20:58:09 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ +import * as pinia from 'pinia'; + +export const store = pinia.createPinia(); diff --git a/smart-app/src/store/modules/system/app-config.js b/smart-app/src/store/modules/system/app-config.js new file mode 100644 index 00000000..c7083983 --- /dev/null +++ b/smart-app/src/store/modules/system/app-config.js @@ -0,0 +1,55 @@ +/* + * 项目的配置信息 + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2022-09-06 20:53:47 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ +import { defineStore } from 'pinia'; +import { appDefaultConfig } from '/@/config/app-config'; +import localStorageKeyConst from '/@/constants/local-storage-key-const'; +import { smartSentry } from '/@/lib/smart-sentry'; +import { localRead } from '/@/utils/local-util'; + +let state = { ...appDefaultConfig }; + +let appConfigStr = localRead(localStorageKeyConst.APP_CONFIG); +let language = appDefaultConfig.language; +if (appConfigStr) { + try { + state = JSON.parse(appConfigStr); + language = state.language; + } catch (e) { + smartSentry.captureError(e); + } +} + +/** + * 获取初始化的语言 + */ +export const getInitializedLanguage = function () { + return language; +}; + +export const useAppConfigStore = defineStore({ + id: 'appConfig', + state: () => ({ + // 读取config下的默认配置 + ...state, + }), + actions: { + reset() { + for (const k in appDefaultConfig) { + this[k] = appDefaultConfig[k]; + } + }, + showHelpDoc() { + this.helpDocFlag = true; + }, + hideHelpDoc() { + this.helpDocFlag = false; + }, + }, +}); diff --git a/smart-app/src/store/modules/system/user.js b/smart-app/src/store/modules/system/user.js new file mode 100644 index 00000000..af9126d1 --- /dev/null +++ b/smart-app/src/store/modules/system/user.js @@ -0,0 +1,84 @@ +/* + * 登录用户 + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2022-09-06 20:55:09 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ +import _ from 'lodash'; +import { defineStore } from 'pinia'; +import { USER_TOKEN } from '/@/constants/local-storage-key-const'; +import { loginApi } from '/@/api/system/login-api'; + +const defaultUserInfo = { + //员工id + employeeId: '', + //登录名 + loginName: '', + //姓名 + actualName: '', + //手机号 + phone: '', + //部门id + departmentId: '', + //部门名词 + departmentName: '', + //是否为超级管理员 + administratorFlag: true, + //上次登录ip + lastLoginIp: '', + //上次登录ip地区 + lastLoginIpRegion: '', + //上次登录 设备 + lastLoginUserAgent: '', + //上次登录时间 + lastLoginTime: '', +}; + +export const useUserStore = defineStore({ + id: 'userStore', + state: () => ({ + ...defaultUserInfo, + }), + getters: { + getToken(state) { + return uni.getStorageSync(USER_TOKEN); + }, + }, + + actions: { + logout() { + this.token = null; + this.setUserLoginInfo(defaultUserInfo); + uni.removeStorage(USER_TOKEN); + }, + clearUserLoginInfo() { + this.setUserLoginInfo(defaultUserInfo); + uni.removeStorage(USER_TOKEN); + }, + async getLoginInfo() { + let res = await loginApi.getLoginInfo(); + this.setUserLoginInfo(res.data); + }, + //设置登录信息 + setUserLoginInfo(data) { + // 用户基本信息 + this.token = data.token; + this.employeeId = data.employeeId; + this.loginName = data.loginName; + this.actualName = data.actualName; + this.phone = data.phone; + this.departmentId = data.departmentId; + this.departmentName = data.departmentName; + this.administratorFlag = data.administratorFlag; + this.lastLoginIp = data.lastLoginIp; + this.lastLoginIpRegion = data.lastLoginIpRegion; + this.lastLoginUserAgent = data.lastLoginUserAgent; + this.lastLoginTime = data.lastLoginTime; + + uni.setStorageSync(USER_TOKEN, data.token); + }, + }, +}); diff --git a/smart-app/src/theme/index.scss b/smart-app/src/theme/index.scss new file mode 100644 index 00000000..edba9f59 --- /dev/null +++ b/smart-app/src/theme/index.scss @@ -0,0 +1,254 @@ +/* + * SmartAdmin 独有的样式 + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2022-09-12 14:43:01 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ + +.scroll-view { + white-space: nowrap; + width: 100%; +} + +.scroll-view-item { + display: inline-block; + width: 570rpx; + height: 128rpx; + overflow: hidden; + font-size: 36rpx; + border-right: 1rpx solid #ededed; + margin-right: 30rpx; +} + +/********************************** 宽度 **********************************/ +.smart-width-100 { + width: 100%; +} + +/********************************** 左间距 **********************************/ +.smart-margin-left5 { + margin-left: 5px; +} + +.smart-margin-left10 { + margin-left: 10px; +} + +.smart-margin-left15 { + margin-left: 15px; +} + +.smart-margin-left20 { + margin-left: 20px; +} + +/********************************** 右间距 **********************************/ +.smart-margin-right5 { + margin-right: 5px; +} + +.smart-margin-right10 { + margin-right: 10px; +} + +.smart-margin-right15 { + margin-right: 15px; +} + +.smart-margin-right20 { + margin-right: 20px; +} + +/******************************** 上间距 ********************************/ +.smart-margin-top5 { + margin-top: 5px; +} + +.smart-margin-top10 { + margin-top: 10px; +} + +.smart-margin-top15 { + margin-top: 15px; +} + +.smart-margin-top20 { + margin-top: 20px; +} + +.smart-margin-top30 { + margin-top: 30px; +} + +.smart-margin-top40 { + margin-top: 40px; +} + +.smart-margin-top50 { + margin-top: 50px; +} + +.smart-margin-top60 { + margin-top: 60px; +} + + +/******************************** 下间距 ********************************/ +.smart-margin-bottom5 { + margin-bottom: 5px; +} + +.smart-margin-bottom10 { + margin-bottom: 10px; +} + +/******************************** 表单 ********************************/ +.smart-form { + height: auto; + padding-bottom: 120px; + + :deep(.uni-forms-item__content) { + display: flex; + align-items: center; + } + + :deep(.uni-forms-item__label) { + font-size: 32rpx; + color: #000000; + padding-top: 28rpx; + } + + :deep(.uni-forms-item) { + margin-bottom: 0 !important; + } + + :deep(.uni-slider-thumb) { + background: #fff !important; + border: 10rpx solid #1a9aff; + box-sizing: border-box; + } + + .smart-form-item { + min-height: 100rpx; + height: auto; + align-items: center; + &:last-child { + border: none; + } + } + + .smart-form-group { + box-sizing: border-box; + width: 100wh; + margin: 20rpx auto 0; + background: #fff; + border-radius: 16rpx; + + .smart-form-group-title { + width: 100%; + height: 84rpx; + background-image: url('/static/images/list/form-list.png'); + background-size: 100% 84rpx; + line-height: 84rpx; + text-indent: 30rpx; + font-size: 32rpx; + color: #323333; + font-weight: bold; + } + + .smart-form-group-content { + padding: 0 30rpx; + } + .input { + font-size: 22rpx; + text-align: right; + width: 100%; + } + } + + .smart-form-submit { + border-top: #eee 1px solid; + height: 80px; + display: flex; + flex-direction: row; + align-items: center; + position: absolute; + bottom: 0; + background-color: white; + width: 100%; + + .smart-form-submit-btn { + margin: 10px; + height: 2.5; + flex: 1; + } + } + + .fixed-bottom-button { + position: fixed; + bottom: 0; + } +} + + +/******************************** 详情 ********************************/ + +.smart-detail { + .smart-detail-card { + background-color: white; + margin-right: auto; + margin-left: auto; + margin-bottom: 15px; + width: 94%; + border-radius: 16rpx; + box-sizing: border-box; + padding: 16rpx 30rpx; + + .smart-detail-card-title { + height: 70rpx; + display: flex; + align-items: center; + font-size: $uni-font-size-lg; + color: #323333; + font-weight: bold; + margin-bottom: 16rpx; + &::before { + content: ''; + height: 32rpx; + width: 3px; + border-radius: 4rpx; + margin-right: 10rpx; + background-color: $uni-color-primary; + } + } + + .smart-detail-card-cell { + display: flex; + min-height: 80rpx; + padding: 10rpx 0; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + border-top: 1rpx solid #ededed; + .smart-detail-card-label { + color: #666666; + font-size: $uni-font-size-lg; + } + .smart-detail-card-value { + font-size: $uni-font-size-lg; + padding: 20rpx 0; + } + } + } +} + + + + + + + + diff --git a/smart-app/src/uni.scss b/smart-app/src/uni.scss new file mode 100644 index 00000000..3c3e21b1 --- /dev/null +++ b/smart-app/src/uni.scss @@ -0,0 +1,131 @@ +/** + * 这里是uni-app内置的常用样式变量 + * + * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 + * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App + * + */ + +/** + * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 + * + * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 + */ + +/* 颜色变量 */ + +/* 行为相关颜色 */ +$uni-color-primary: #007aff; +$uni-color-success: #4cd964; +$uni-color-warning: #f0ad4e; +$uni-color-error: #dd524d; + +/* 文字基本颜色 */ +$uni-text-color: #333; // 基本色 +$uni-text-color-inverse: #fff; // 反色 +$uni-text-color-grey: #999; // 辅助灰色,如加载更多的提示信息 +$uni-text-color-placeholder: #808080; +$uni-text-color-disable: #c0c0c0; + +/* 背景颜色 */ +$uni-bg-color: #fff; +$uni-bg-color-grey: #f8f8f8; +$uni-bg-color-hover: #f1f1f1; // 点击状态颜色 +$uni-bg-color-mask: rgba(0, 0, 0, 0.4); // 遮罩颜色 + +/* 边框颜色 */ +$uni-border-color: #c8c7cc; + +/* 尺寸变量 */ + +/* 文字尺寸 */ +$uni-font-size-sm: 12px; +$uni-font-size-base: 14px; +$uni-font-size-lg: 16px; + +/* 图片尺寸 */ +$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; + + + +// 字体 ------------------- begin ------------- +$main-size: 14px; // 主要字体大小 +$title-size: 17px;// 标题字体大小 +$small-size: 12px; // 辅助字体大小 +// 字体 ------------------- end ------------- + +// 颜色 ------------------- begin ------------- +$main-color: #1A9AFF; //主色调 +$main-background: #F4F4F4; //主色背景色 +$main-font-color: #444444;// 字体一级颜色 +$second-font-color: #777777; // 字体二级颜色 +$border-color: #EDEDED; // 边框颜色 +$background-color: #F5F6F8; // 背景颜色 +$page-bg-color: #F7F8F9; // 页面背景灰色 +$title-text-color: #444444;// 列表顶部标题颜色 +$item-text-color: #353535; // 块标题颜色 +$main-orange-color: #FF6C00; // 橙色 +$main-orange-background: #FFF0ED;// 橙色背景 +$main-green-color: #1CE36D; // 绿色 +$main-green-background: #E5F8E9;// 绿色背景 +$main-red-color: #FF3924; // 红色 +$auxiliary-color: #CCCCCC; // 辅助颜色 + +$toast-color: #A1AEBE; // 提示颜色 +$toast-color-low: #D0D5DB; // 弱提示颜色 +$weak-background-color: #F9FAFC; // 弱的颜色 +$gray-color-low: #CCC; // 浅灰色 +$linear-color: linear-gradient(270deg,#2e9aff, #007ff2); // 主要渐变色 +$error-color: #F26158; // 错误颜色 +$answer-error-bg-color: #fffaf9; // 做题选项答错背景 +$answer-right-bg-color: #f6fbff; // 做题选项答对背景 +$collapse-bg-color: #F3F6FB; // 折叠面板二级背景颜色 +// 颜色 ------------------- end ------------- + + +// 样式 ------------------- begin ------------- +// 这里导出的样式在APP端无效,APP端不要再引用了 +:export { + mainColor: $main-color; + backgroundColor:$background-color; + error: $error-color; + mainFontColor: $main-font-color; + auxiliaryFontColor: $auxiliary-color; + mainBorder: $border-color; + secondFontColor:$second-font-color; + collapseBgColor:$collapse-bg-color; + toastColor:$toast-color; + textColorWhite:$main-background; + toastColorLow: $toast-color-low; + titleTextColor: $title-text-color; + grayColorLow:$gray-color-low; +} diff --git a/smart-app/src/uni_modules/uni-data-picker/changelog.md b/smart-app/src/uni_modules/uni-data-picker/changelog.md new file mode 100644 index 00000000..8aaad241 --- /dev/null +++ b/smart-app/src/uni_modules/uni-data-picker/changelog.md @@ -0,0 +1,77 @@ +## 2.0.0(2023-12-14) +- 新增 支持 uni-app-x +## 1.1.2(2023-04-11) +- 修复 更改 modelValue 报错的 bug +- 修复 v-for 未使用 key 值控制台 warning +## 1.1.1(2023-02-21) +- 修复代码合并时引发 value 属性为空时不渲染数据的问题 +## 1.1.0(2023-02-15) +- 修复 localdata 不支持动态更新的bug +## 1.0.9(2023-02-15) +- 修复 localdata 不支持动态更新的bug +## 1.0.8(2022-09-16) +- 可以使用 uni-scss 控制主题色 +## 1.0.7(2022-07-06) +- 优化 pc端图标位置不正确的问题 +## 1.0.6(2022-07-05) +- 优化 显示样式 +## 1.0.5(2022-07-04) +- 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug +## 1.0.4(2022-04-19) +- 修复 字节小程序 本地数据无法选择下一级的Bug +## 1.0.3(2022-02-25) +- 修复 nvue 不支持的 v-show 的 bug +## 1.0.2(2022-02-25) +- 修复 条件编译 nvue 不支持的 css 样式 +## 1.0.1(2021-11-23) +- 修复 由上个版本引发的map、v-model等属性不生效的bug +## 1.0.0(2021-11-19) +- 优化 组件 UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-picker](https://uniapp.dcloud.io/component/uniui/uni-data-picker) +## 0.4.9(2021-10-28) +- 修复 VUE2 v-model 概率无效的 bug +## 0.4.8(2021-10-27) +- 修复 v-model 概率无效的 bug +## 0.4.7(2021-10-25) +- 新增 属性 spaceInfo 服务空间配置 HBuilderX 3.2.11+ +- 修复 树型 uniCloud 数据类型为 int 时报错的 bug +## 0.4.6(2021-10-19) +- 修复 非 VUE3 v-model 为 0 时无法选中的 bug +## 0.4.5(2021-09-26) +- 新增 清除已选项的功能(通过 clearIcon 属性配置是否显示按钮),同时提供 clear 方法以供调用,二者等效 +- 修复 readonly 为 true 时报错的 bug +## 0.4.4(2021-09-26) +- 修复 上一版本造成的 map 属性失效的 bug +- 新增 ellipsis 属性,支持配置 tab 选项长度过长时是否自动省略 +## 0.4.3(2021-09-24) +- 修复 某些情况下级联未触发的 bug +## 0.4.2(2021-09-23) +- 新增 提供 show 和 hide 方法,开发者可以通过 ref 调用 +- 新增 选项内容过长自动添加省略号 +## 0.4.1(2021-09-15) +- 新增 map 属性 字段映射,将 text/value 映射到数据中的其他字段 +## 0.4.0(2021-07-13) +- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 0.3.5(2021-06-04) +- 修复 无法加载云端数据的问题 +## 0.3.4(2021-05-28) +- 修复 v-model 无效问题 +- 修复 loaddata 为空数据组时加载时间过长问题 +- 修复 上个版本引出的本地数据无法选择带有 children 的 2 级节点 +## 0.3.3(2021-05-12) +- 新增 组件示例地址 +## 0.3.2(2021-04-22) +- 修复 非树形数据有 where 属性查询报错的问题 +## 0.3.1(2021-04-15) +- 修复 本地数据概率无法回显时问题 +## 0.3.0(2021-04-07) +- 新增 支持云端非树形表结构数据 +- 修复 根节点 parent_field 字段等于 null 时选择界面错乱问题 +## 0.2.0(2021-03-15) +- 修复 nodeclick、popupopened、popupclosed 事件无法触发的问题 +## 0.1.9(2021-03-09) +- 修复 微信小程序某些情况下无法选择的问题 +## 0.1.8(2021-02-05) +- 优化 部分样式在 nvue 上的兼容表现 +## 0.1.7(2021-02-05) +- 调整为 uni_modules 目录规范 diff --git a/smart-app/src/uni_modules/uni-data-picker/components/uni-data-picker/keypress.js b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-picker/keypress.js new file mode 100644 index 00000000..6ef26a26 --- /dev/null +++ b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-picker/keypress.js @@ -0,0 +1,45 @@ +// #ifdef H5 +export default { + name: 'Keypress', + props: { + disable: { + type: Boolean, + default: false + } + }, + mounted () { + const keyNames = { + esc: ['Esc', 'Escape'], + tab: 'Tab', + enter: 'Enter', + space: [' ', 'Spacebar'], + up: ['Up', 'ArrowUp'], + left: ['Left', 'ArrowLeft'], + right: ['Right', 'ArrowRight'], + down: ['Down', 'ArrowDown'], + delete: ['Backspace', 'Delete', 'Del'] + } + const listener = ($event) => { + if (this.disable) { + return + } + const keyName = Object.keys(keyNames).find(key => { + const keyName = $event.key + const value = keyNames[key] + return value === keyName || (Array.isArray(value) && value.includes(keyName)) + }) + if (keyName) { + // 避免和其他按键事件冲突 + setTimeout(() => { + this.$emit(keyName, {}) + }, 0) + } + } + document.addEventListener('keyup', listener) + this.$once('hook:beforeDestroy', () => { + document.removeEventListener('keyup', listener) + }) + }, + render: () => {} +} +// #endif diff --git a/smart-app/src/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.uvue b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.uvue new file mode 100644 index 00000000..82031e1d --- /dev/null +++ b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.uvue @@ -0,0 +1,380 @@ + + + + + diff --git a/smart-app/src/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue new file mode 100644 index 00000000..179a4e0b --- /dev/null +++ b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-picker/uni-data-picker.vue @@ -0,0 +1,551 @@ + + + + + diff --git a/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/loading.uts b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/loading.uts new file mode 100644 index 00000000..baa0dfff --- /dev/null +++ b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/loading.uts @@ -0,0 +1 @@ +export const imgbase : string = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QzlBMzU3OTlEOUM0MTFFOUI0NTZDNERBQURBQzI4RkUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QzlBMzU3OUFEOUM0MTFFOUI0NTZDNERBQURBQzI4RkUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDOUEzNTc5N0Q5QzQxMUU5QjQ1NkM0REFBREFDMjhGRSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpDOUEzNTc5OEQ5QzQxMUU5QjQ1NkM0REFBREFDMjhGRSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pt+ALSwAAA6CSURBVHja1FsLkFZVHb98LM+F5bHL8khA1iSeiyQBCRM+YGqKUnnJTDLGI0BGZlKDIU2MMglUiDApEZvSsZnQtBRJtKwQNKQMFYeRDR10WOLd8ljYXdh+v8v5fR3Od+797t1dnOnO/Ofce77z+J//+b/P+ZqtXbs2sJ9MJhNUV1cHJ06cCJo3bx7EPc2aNcvpy7pWrVoF+/fvDyoqKoI2bdoE9fX1F7TjN8a+EXBn/fkfvw942Tf+wYMHg9mzZwfjxo0LDhw4EPa1x2MbFw/fOGfPng1qa2tzcCkILsLDydq2bRsunpOTMM7TD/W/tZDZhPdeKD+yGxHhdu3aBV27dg3OnDlzMVANMheLAO3btw8KCwuDmpoaX5OxbgUIMEq7K8IcPnw4KCsrC/r37x8cP378/4cAXAB3vqSkJMuiDhTkw+XcuXNhOWbMmKBly5YhUT8xArhyFvP0BfwRsAuwxJZJsm/nzp2DTp06he/OU+cZ64K6o0ePBkOHDg2GDx8e6gEbJ5Q/NHNuAJQ1hgBeHUDlR7nVTkY8rQAvAi4z34vR/mPs1FoRsaCgIJThI0eOBC1atEiFGGV+5MiRoS45efJkqFjJFXV1dQuA012m2WcwTw98fy6CqBdsaiIO4CScrGPHjvk4odhavPquRtFWXEC25VgkREKOCh/qDSq+vn37htzD/mZTOmOc5U7zKzBPEedygWshcDyWvs30igAbU+6oyMgJBCFhwQE0fccxN60Ay9iebbjoDh06hMowjQxT4fXq1SskArmHZpkArvixp/kWzHdMeArExSJEaiXIjjRjRJ4DaAGWpibLzXN3Fm1vA5teBgh3j1Rv3bp1YgKwPdmf2p9zcyNYYgPKMfY0T5f5nNYdw158nJ8QawW4CLKwiOBSEgO/hok2eBydR+3dYH+PLxA5J8Vv0KBBwenTp0P2JWAx6+yFEBfs8lMY+y0SWMBNI9E4ThKi58VKTg3FQZS1RQF1cz27eC0QHMu+3E0SkUowjhVt5VdaWhp07949ZHv2Qd1EjDXM2cla1M0nl3GxAs3J9yREzyTdFVKVFOaE9qRA8GM0WebRuo9JGZKA7Mv2SeS/Z8+eoQ9BArMfFrLGo6jvxbhHbJZnKX2Rzz1O7QhJJ9Cs2ZMaWIyq/zhdeqPNfIoHd58clIQD+JSXl4dKlyIAuBdVXZwFVWKspSSoxE++h8x4k3uCnEhE4I5KwRiFWGOU0QWKiCYLbdoRMRKAu2kQ9vkfLU6dOhX06NEjlH+yMRZSinnuyWnYosVcji8CEA/6Cg2JF+IIUBqnGKUTCNwtwBN4f89RiK1R96DEgO2o0NDmtEdvVFdVVYV+P3UAPUEs6GFwV3PHmXkD4vh74iDFJysVI/MlaQhwKeBNTLYX5VuA8T4/gZxA4MRGFxDB6R7OmYPfyykGRJbyie+XnGYnQIC/coH9+vULiYrxrkL9ZA9+0ykaHIfEpM7ge8TiJ2CsHYwyMfafAF1yCGBHYIbCVDjDjKt7BeB51D+LgQa6OkG7IDYEEtvQ7lnXLKLtLdLuJBpE4gPUXcW2+PkZwOex+4cGDhwYDBkyRL7/HFcEwUGPo/8uWRUpYnfxGHco8HkewLHLyYmAawAPuIFZxhOpDfJQ8gbUv41yORAptMWBNr6oqMhWird5+u+iHmBb2nhjDV7HWBNQTgK8y11l5NetWzc5ULscAtSj7nbNI0skhWeUZCc0W4nyH/jO4Vz0u1IeYhbk4AiwM6tjxIWByHsoZ9qcIBPJd/y+DwPfBESOmCa/QF3WiZHucLlEDpNxcNhmheEOPgdQNx6/VZFQzFZ5TN08AHXQt2Ii3EdyFuUsPtTcGPhW5iMiCNELvz+Gdn9huG4HUJaW/w3g0wxV0XaG7arG2WeKiUWYM4Y7GO5ezshTARbbWGw/DvXkpp/ivVvE0JVoMxN4rpGzJMhE5Pl+xlATsDIqikP9F9D2z3h9nOksEUFhK+qO4rcPkoalMQ/HqJLIyb3F3JdjrCcw1yZ8joyJLR5gCo54etlag7qIoeNh1N1BRYj3DTFJ0elotxPlVzkGuYAmL0VSJVGAJA41c4Z6A3BzTLfn0HYwYKEI6CUAMzZEWvLsIcQOo1AmmyyM72nHJCfYsogflGV6jEk9vyQZXSuq6w4c16NsGcGZbwOPr+H1RkOk2LEzjNepxQkihHSCQ4ynAYNRx2zMKV92CQMWqj8J0BRE8EShxRFN6YrfCRhC0x3r/Zm4IbQCcmJoV0kMamllccR6FjHqUC5F2R/wS2dcymOlfAKOS4KmzQb5cpNC2MC7JhVn5wjXoJ44rYhLh8n0eXOCorJxa7POjbSlCGVczr34/RsAmrcvo9s+wGp3tzVhntxiXiJ4nvEYb4FJkf0O8HocAePmLvCxnL0AORraVekJk6TYjDabRVXfRE2lCN1h6ZQRN1+InUbsCpKwoBZHh0dODN9JBCUffItXxEavTQkUtnfTVAplCWL3JISz29h4NjotnuSsQKJCk8dF+kJR6RARjrqFVmfPnj3ZbK8cIJ0msd6jgHPGtfVTQ8VLmlvh4mct9sobRmPic0DyDQQnx/NlfYUgyz59+oScsH379pAwXABD32nTpoUHIToESeI5mnbE/UqDdyLcafEBf2MCqgC7NwxIbMREJQ0g4D4sfJwnD+AmRrII05cfMWJE+L1169bQr+fip06dGp4oJ83lmYd5wj/EmMa4TaHivo4EeCguYZBnkB5g2aWA69OIEnUHOaGysjIYMGBAMGnSpODYsWPZwCpFmm4lNq+4gSLQA7jcX8DwtjEyRC8wjabnXEx9kfWnTJkSJkAo90xpJVV+FmcVNeYAF5zWngS4C4O91MBxmAv8blLEpbjI5sz9MTdAhcgkCT1RO8mZkAjfiYpTEvStAS53Uw1vAiUGgZ3GpuQEYvoiBqlIan7kSDHnTwJQFNiPu0+5VxCVYhcZIjNrdXUDdp+Eq5AZ3Gkg8QAyVZRZIk4Tl4QAbF9cXJxNYZMAtAokgs4BrNxEpCtteXg7DDTMDKYNSuQdKsnJBek7HxewvxaosWxLYXtw+cJp18217wql4aKCfBNoEu0O5VU+PhctJ0YeXD4C6JQpyrlpSLTojpGGGN5YwNziChdIZLk4lvLcFJ9jMX3QdiImY9bmGQU+TRUL5CHITTRlgF8D9ouD1MfmLoEPl5xokIumZ2cfgMpHt47IW9N64Hsh7wQYYjyIugWuF5fCqYncXRd5vPMWyizzvhi/32+nvG0dZc9vR6fZOu0md5e+uC408FvKSIOZwXlGvxPv95izA2Vtvg1xKFWARI+vMX66HUhpQQb643uW1bSjuTWyw2SBvDrBvjFic1eGGlz5esq3ko9uSIlBRqPuFcCv8F4WIcN12nVaBd0SaYwI6PDDImR11JkqgHcPmQssjxIn6bUshygDFJUTxPMpHk+jfjPgupgdnYV2R/g7xSjtpah8RJBewhwf0gGK6XI92u4wXFEU40afJ4DN4h5LcAd+40HI3JgJecuT0c062W0i2hQJUTcxan3/CMW1PF2K6bbA+Daz4xRs1D3Br1Cm0OihKCqizW78/nXAF/G5TXrEcVzaNMH6CyMswqsAHqDyDLEyou8lwOXnKF8DjI6KjV3KzMBiXkDH8ij/H214J5A596ekrZ3F0zXlWeL7+P5eUrNo3/QwC15uxthuzidy7DzKRwEDaAViiDgKbTbz7CJnzo0bN7pIfIiid8SuPwn25o3QCmpnyjlZkyxPP8EomCJzrGb7GJMx7tNsq4MT2xMUYaiErZOluTzKsnz3gwCeCZyVRZJfYplNEokEjwrPtxlxjeYAk+F1F74VAzPxQRNYYdtpOUvWs8J1sGhBJMNsb7igN8plJs1eSmLIhLKE4rvaCX27gOhLpLOsIzJ7qn/i+wZzcvSOZ23/du8TZjwV8zHIXoP4R3ifBxiFz1dcVpa3aPntPE+c6TmIWE9EtcMmAcPdWAhYhAXxcLOQi9L1WhD1Sc8p1d2oL7XGiRKp8F4A2i8K/nfI+y/gsTDJ/YC/8+AD5Uh04KHiGl+cIFPnBDDrPMjwRGkLXyxO4VGbfQWnDH2v0bVWE3C9QOXlepbgjEfIJQI6XDG3z5ahD9cw2pS78ipB85wyScNTvsVzlzzhL8/jRrnmVjfFJK/m3m4nj9vbgQTguT8XZTjsm672R5uJKEaQmBI/c58gyus8ZDagLpEVSJBIyHp4jn++xqPV71OgQgJYEWOtZ/haxRtKmWOBu8xdBLftWltsY84zE6WIEy/eIOWL+BaayMx+KHtL7EAkqdNDLiEXmEMUHniedtJqg9HmZtfvt26vNi0BdG3Ft3g8ZOf7PAu59TxtzivLNIekyi+wD1i8CuUiD9FXAa8C+/xS3JPmZnomyc7H+fb4/Se0bk41Fel621r4cgVxbq91V4jVqwB7HTe2M7jgB+QWHavZkDRPmZcASoZEmBx6i75bGjPcMdL4/VKGFAGWZkGzPG0XAbdL9A81G5LOmUnC9hHKJeO7dcUMjblSl12867ElFTtaGl20xvvLGPdVz/8TVuU7y0x1PG7vtNg24oz9Uo/Z412++VFWI7Fcog9tu9Lm6gvRmIPv9x1xmQAu6RDkXtbOtlGEmpgD5Nvnyc0dcv0EE6cfdi1HmhMf9wDF3k3gtRvEedhxjpgfqPb9PU9iEJHnyOUA7bQUXh6kq/D7l2iTjWv7XOD530BDr8jIrus+srXjt4MzumJMHuTsBa63YKE1+RR5lBjEikCCnWKWiHdzOgKO+nRIBAF88za/IFmJ3eMZov4CYxGBabcpGL8EYx+SeMXJeRwHNsV/h+vdxeuhEpN3ZyNY78Gm2fknJxVGhyjixPiQvVkNzT1elD9Py/aTAL64Hb9vcYmC9zfdXdT/C1LeGbg4rnBaAihDFJH12W5ulfNCNe/xTsP3bp8ikzJs5BF+5PNfAQYAPaseTdsEcaYAAAAASUVORK5CYII=' \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js new file mode 100644 index 00000000..cfae22a4 --- /dev/null +++ b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.js @@ -0,0 +1,622 @@ +export default { + props: { + localdata: { + type: [Array, Object], + default () { + return [] + } + }, + spaceInfo: { + type: Object, + default () { + return {} + } + }, + collection: { + type: String, + default: '' + }, + action: { + type: String, + default: '' + }, + field: { + type: String, + default: '' + }, + orderby: { + type: String, + default: '' + }, + where: { + type: [String, Object], + default: '' + }, + pageData: { + type: String, + default: 'add' + }, + pageCurrent: { + type: Number, + default: 1 + }, + pageSize: { + type: Number, + default: 500 + }, + getcount: { + type: [Boolean, String], + default: false + }, + getone: { + type: [Boolean, String], + default: false + }, + gettree: { + type: [Boolean, String], + default: false + }, + manual: { + type: Boolean, + default: false + }, + value: { + type: [Array, String, Number], + default () { + return [] + } + }, + modelValue: { + type: [Array, String, Number], + default () { + return [] + } + }, + preload: { + type: Boolean, + default: false + }, + stepSearh: { + type: Boolean, + default: true + }, + selfField: { + type: String, + default: '' + }, + parentField: { + type: String, + default: '' + }, + multiple: { + type: Boolean, + default: false + }, + map: { + type: Object, + default () { + return { + text: "text", + value: "value" + } + } + } + }, + data() { + return { + loading: false, + errorMessage: '', + loadMore: { + contentdown: '', + contentrefresh: '', + contentnomore: '' + }, + dataList: [], + selected: [], + selectedIndex: 0, + page: { + current: this.pageCurrent, + size: this.pageSize, + count: 0 + } + } + }, + computed: { + isLocalData() { + return !this.collection.length; + }, + isCloudData() { + return this.collection.length > 0; + }, + isCloudDataList() { + return (this.isCloudData && (!this.parentField && !this.selfField)); + }, + isCloudDataTree() { + return (this.isCloudData && this.parentField && this.selfField); + }, + dataValue() { + let isModelValue = Array.isArray(this.modelValue) ? (this.modelValue.length > 0) : (this.modelValue !== null || + this.modelValue !== undefined); + return isModelValue ? this.modelValue : this.value; + }, + hasValue() { + if (typeof this.dataValue === 'number') { + return true + } + return (this.dataValue != null) && (this.dataValue.length > 0) + } + }, + created() { + this.$watch(() => { + var al = []; + ['pageCurrent', + 'pageSize', + 'spaceInfo', + 'value', + 'modelValue', + 'localdata', + 'collection', + 'action', + 'field', + 'orderby', + 'where', + 'getont', + 'getcount', + 'gettree' + ].forEach(key => { + al.push(this[key]) + }); + return al + }, (newValue, oldValue) => { + let needReset = false + for (let i = 2; i < newValue.length; i++) { + if (newValue[i] != oldValue[i]) { + needReset = true + break + } + } + if (newValue[0] != oldValue[0]) { + this.page.current = this.pageCurrent + } + this.page.size = this.pageSize + + this.onPropsChange() + }) + this._treeData = [] + }, + methods: { + onPropsChange() { + this._treeData = []; + }, + + // 填充 pickview 数据 + async loadData() { + if (this.isLocalData) { + this.loadLocalData(); + } else if (this.isCloudDataList) { + this.loadCloudDataList(); + } else if (this.isCloudDataTree) { + this.loadCloudDataTree(); + } + }, + + // 加载本地数据 + async loadLocalData() { + this._treeData = []; + this._extractTree(this.localdata, this._treeData); + + let inputValue = this.dataValue; + if (inputValue === undefined) { + return; + } + + if (Array.isArray(inputValue)) { + inputValue = inputValue[inputValue.length - 1]; + if (typeof inputValue === 'object' && inputValue[this.map.value]) { + inputValue = inputValue[this.map.value]; + } + } + + this.selected = this._findNodePath(inputValue, this.localdata); + }, + + // 加载 Cloud 数据 (单列) + async loadCloudDataList() { + if (this.loading) { + return; + } + this.loading = true; + + try { + let response = await this.getCommand(); + let responseData = response.result.data; + + this._treeData = responseData; + + this._updateBindData(); + this._updateSelected(); + + this.onDataChange(); + } catch (e) { + this.errorMessage = e; + } finally { + this.loading = false; + } + }, + + // 加载 Cloud 数据 (树形) + async loadCloudDataTree() { + if (this.loading) { + return; + } + this.loading = true; + + try { + let commandOptions = { + field: this._cloudDataPostField(), + where: this._cloudDataTreeWhere() + }; + if (this.gettree) { + commandOptions.startwith = `${this.selfField}=='${this.dataValue}'`; + } + + let response = await this.getCommand(commandOptions); + let responseData = response.result.data; + + this._treeData = responseData; + this._updateBindData(); + this._updateSelected(); + + this.onDataChange(); + } catch (e) { + this.errorMessage = e; + } finally { + this.loading = false; + } + }, + + // 加载 Cloud 数据 (节点) + async loadCloudDataNode(callback) { + if (this.loading) { + return; + } + this.loading = true; + + try { + let commandOptions = { + field: this._cloudDataPostField(), + where: this._cloudDataNodeWhere() + }; + + let response = await this.getCommand(commandOptions); + let responseData = response.result.data; + + callback(responseData); + } catch (e) { + this.errorMessage = e; + } finally { + this.loading = false; + } + }, + + // 回显 Cloud 数据 + getCloudDataValue() { + if (this.isCloudDataList) { + return this.getCloudDataListValue(); + } + + if (this.isCloudDataTree) { + return this.getCloudDataTreeValue(); + } + }, + + // 回显 Cloud 数据 (单列) + getCloudDataListValue() { + // 根据 field's as value标识匹配 where 条件 + let where = []; + let whereField = this._getForeignKeyByField(); + if (whereField) { + where.push(`${whereField} == '${this.dataValue}'`) + } + + where = where.join(' || '); + + if (this.where) { + where = `(${this.where}) && (${where})` + } + + return this.getCommand({ + field: this._cloudDataPostField(), + where + }).then((res) => { + this.selected = res.result.data; + return res.result.data; + }); + }, + + // 回显 Cloud 数据 (树形) + getCloudDataTreeValue() { + return this.getCommand({ + field: this._cloudDataPostField(), + getTreePath: { + startWith: `${this.selfField}=='${this.dataValue}'` + } + }).then((res) => { + let treePath = []; + this._extractTreePath(res.result.data, treePath); + this.selected = treePath; + return treePath; + }); + }, + + getCommand(options = {}) { + /* eslint-disable no-undef */ + let db = uniCloud.database(this.spaceInfo) + + const action = options.action || this.action + if (action) { + db = db.action(action) + } + + const collection = options.collection || this.collection + db = db.collection(collection) + + const where = options.where || this.where + if (!(!where || !Object.keys(where).length)) { + db = db.where(where) + } + + const field = options.field || this.field + if (field) { + db = db.field(field) + } + + const orderby = options.orderby || this.orderby + if (orderby) { + db = db.orderBy(orderby) + } + + const current = options.pageCurrent !== undefined ? options.pageCurrent : this.page.current + const size = options.pageSize !== undefined ? options.pageSize : this.page.size + const getCount = options.getcount !== undefined ? options.getcount : this.getcount + const getTree = options.gettree !== undefined ? options.gettree : this.gettree + + const getOptions = { + getCount, + getTree + } + if (options.getTreePath) { + getOptions.getTreePath = options.getTreePath + } + + db = db.skip(size * (current - 1)).limit(size).get(getOptions) + + return db + }, + + _cloudDataPostField() { + let fields = [this.field]; + if (this.parentField) { + fields.push(`${this.parentField} as parent_value`); + } + return fields.join(','); + }, + + _cloudDataTreeWhere() { + let result = [] + let selected = this.selected + let parentField = this.parentField + if (parentField) { + result.push(`${parentField} == null || ${parentField} == ""`) + } + if (selected.length) { + for (var i = 0; i < selected.length - 1; i++) { + result.push(`${parentField} == '${selected[i].value}'`) + } + } + + let where = [] + if (this.where) { + where.push(`(${this.where})`) + } + + if (result.length) { + where.push(`(${result.join(' || ')})`) + } + + return where.join(' && ') + }, + + _cloudDataNodeWhere() { + let where = [] + let selected = this.selected; + if (selected.length) { + where.push(`${this.parentField} == '${selected[selected.length - 1].value}'`); + } + + where = where.join(' || '); + + if (this.where) { + return `(${this.where}) && (${where})` + } + + return where + }, + + _getWhereByForeignKey() { + let result = [] + let whereField = this._getForeignKeyByField(); + if (whereField) { + result.push(`${whereField} == '${this.dataValue}'`) + } + + if (this.where) { + return `(${this.where}) && (${result.join(' || ')})` + } + + return result.join(' || ') + }, + + _getForeignKeyByField() { + let fields = this.field.split(','); + let whereField = null; + for (let i = 0; i < fields.length; i++) { + const items = fields[i].split('as'); + if (items.length < 2) { + continue; + } + if (items[1].trim() === 'value') { + whereField = items[0].trim(); + break; + } + } + return whereField; + }, + + _updateBindData(node) { + const { + dataList, + hasNodes + } = this._filterData(this._treeData, this.selected) + + let isleaf = this._stepSearh === false && !hasNodes + + if (node) { + node.isleaf = isleaf + } + + this.dataList = dataList + this.selectedIndex = dataList.length - 1 + + if (!isleaf && this.selected.length < dataList.length) { + this.selected.push({ + value: null, + text: "请选择" + }) + } + + return { + isleaf, + hasNodes + } + }, + + _updateSelected() { + let dl = this.dataList + let sl = this.selected + let textField = this.map.text + let valueField = this.map.value + for (let i = 0; i < sl.length; i++) { + let value = sl[i].value + let dl2 = dl[i] + for (let j = 0; j < dl2.length; j++) { + let item2 = dl2[j] + if (item2[valueField] === value) { + sl[i].text = item2[textField] + break + } + } + } + }, + + _filterData(data, paths) { + let dataList = [] + let hasNodes = true + + dataList.push(data.filter((item) => { + return (item.parent_value === null || item.parent_value === undefined || item.parent_value === '') + })) + for (let i = 0; i < paths.length; i++) { + let value = paths[i].value + let nodes = data.filter((item) => { + return item.parent_value === value + }) + + if (nodes.length) { + dataList.push(nodes) + } else { + hasNodes = false + } + } + + return { + dataList, + hasNodes + } + }, + + _extractTree(nodes, result, parent_value) { + let list = result || [] + let valueField = this.map.value + for (let i = 0; i < nodes.length; i++) { + let node = nodes[i] + + let child = {} + for (let key in node) { + if (key !== 'children') { + child[key] = node[key] + } + } + if (parent_value !== null && parent_value !== undefined && parent_value !== '') { + child.parent_value = parent_value + } + result.push(child) + + let children = node.children + if (children) { + this._extractTree(children, result, node[valueField]) + } + } + }, + + _extractTreePath(nodes, result) { + let list = result || [] + for (let i = 0; i < nodes.length; i++) { + let node = nodes[i] + + let child = {} + for (let key in node) { + if (key !== 'children') { + child[key] = node[key] + } + } + result.push(child) + + let children = node.children + if (children) { + this._extractTreePath(children, result) + } + } + }, + + _findNodePath(key, nodes, path = []) { + let textField = this.map.text + let valueField = this.map.value + for (let i = 0; i < nodes.length; i++) { + let node = nodes[i] + let children = node.children + let text = node[textField] + let value = node[valueField] + + path.push({ + value, + text + }) + + if (value === key) { + return path + } + + if (children) { + const p = this._findNodePath(key, children, path) + if (p.length) { + return p + } + } + + path.pop() + } + return [] + } + } +} diff --git a/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.uts b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.uts new file mode 100644 index 00000000..372795d3 --- /dev/null +++ b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-picker.uts @@ -0,0 +1,693 @@ +export type PaginationType = { + current : number, + size : number, + count : number +} + +export type LoadMoreType = { + contentdown : string, + contentrefresh : string, + contentnomore : string +} + +export type SelectedItemType = { + name : string, + value : string, +} + +export type GetCommandOptions = { + collection ?: UTSJSONObject, + field ?: string, + orderby ?: string, + where ?: any, + pageData ?: string, + pageCurrent ?: number, + pageSize ?: number, + getCount ?: boolean, + getTree ?: any, + getTreePath ?: UTSJSONObject, + startwith ?: string, + limitlevel ?: number, + groupby ?: string, + groupField ?: string, + distinct ?: boolean, + pageIndistinct ?: boolean, + foreignKey ?: string, + loadtime ?: string, + manual ?: boolean +} + +const DefaultSelectedNode = { + text: '请选择', + value: '' +} + +export const dataPicker = defineMixin({ + props: { + localdata: { + type: Array as PropType>, + default: [] as Array + }, + collection: { + type: Object, + default: '' + }, + field: { + type: String, + default: '' + }, + orderby: { + type: String, + default: '' + }, + where: { + type: Object, + default: '' + }, + pageData: { + type: String, + default: 'add' + }, + pageCurrent: { + type: Number, + default: 1 + }, + pageSize: { + type: Number, + default: 20 + }, + getcount: { + type: Boolean, + default: false + }, + gettree: { + type: Object, + default: '' + }, + gettreepath: { + type: Object, + default: '' + }, + startwith: { + type: String, + default: '' + }, + limitlevel: { + type: Number, + default: 10 + }, + groupby: { + type: String, + default: '' + }, + groupField: { + type: String, + default: '' + }, + distinct: { + type: Boolean, + default: false + }, + pageIndistinct: { + type: Boolean, + default: false + }, + foreignKey: { + type: String, + default: '' + }, + loadtime: { + type: String, + default: 'auto' + }, + manual: { + type: Boolean, + default: false + }, + preload: { + type: Boolean, + default: false + }, + stepSearh: { + type: Boolean, + default: true + }, + selfField: { + type: String, + default: '' + }, + parentField: { + type: String, + default: '' + }, + multiple: { + type: Boolean, + default: false + }, + value: { + type: Object, + default: '' + }, + modelValue: { + type: Object, + default: '' + }, + defaultProps: { + type: Object as PropType, + } + }, + data() { + return { + loading: false, + error: null as UniCloudError | null, + treeData: [] as Array, + selectedIndex: 0, + selectedNodes: [] as Array, + selectedPages: [] as Array[], + selectedValue: '', + selectedPaths: [] as Array, + pagination: { + current: 1, + size: 20, + count: 0 + } as PaginationType + } + }, + computed: { + mappingTextName() : string { + // TODO + return (this.defaultProps != null) ? this.defaultProps!.getString('text', 'text') : 'text' + }, + mappingValueName() : string { + // TODO + return (this.defaultProps != null) ? this.defaultProps!.getString('value', 'value') : 'value' + }, + currentDataList() : Array { + if (this.selectedIndex > this.selectedPages.length - 1) { + return [] as Array + } + return this.selectedPages[this.selectedIndex] + }, + isLocalData() : boolean { + return this.localdata.length > 0 + }, + isCloudData() : boolean { + return this._checkIsNotNull(this.collection) + }, + isCloudDataList() : boolean { + return (this.isCloudData && (this.parentField.length == 0 && this.selfField.length == 0)) + }, + isCloudDataTree() : boolean { + return (this.isCloudData && this.parentField.length > 0 && this.selfField.length > 0) + }, + dataValue() : any { + return this.hasModelValue ? this.modelValue : this.value + }, + hasCloudTreeData() : boolean { + return this.treeData.length > 0 + }, + hasModelValue() : boolean { + if (typeof this.modelValue == 'string') { + const valueString = this.modelValue as string + return (valueString.length > 0) + } else if (Array.isArray(this.modelValue)) { + const valueArray = this.modelValue as Array + return (valueArray.length > 0) + } + return false + }, + hasCloudDataValue() : boolean { + if (typeof this.dataValue == 'string') { + const valueString = this.dataValue as string + return (valueString.length > 0) + } + return false + } + }, + created() { + this.pagination.current = this.pageCurrent + this.pagination.size = this.pageSize + + this.$watch( + () : any => [ + this.pageCurrent, + this.pageSize, + this.localdata, + this.value, + this.collection, + this.field, + this.getcount, + this.orderby, + this.where, + this.groupby, + this.groupField, + this.distinct + ], + (newValue : Array, oldValue : Array) => { + this.pagination.size = this.pageSize + if (newValue[0] !== oldValue[0]) { + this.pagination.current = this.pageCurrent + } + + this.onPropsChange() + } + ) + }, + methods: { + onPropsChange() { + this.selectedIndex = 0 + this.treeData.length = 0 + this.selectedNodes.length = 0 + this.selectedPages.length = 0 + this.selectedPaths.length = 0 + + // 加载数据 + this.$nextTick(() => { + this.loadData() + }) + }, + + onTabSelect(index : number) { + this.selectedIndex = index + }, + + onNodeClick(nodeData : UTSJSONObject) { + if (nodeData.getBoolean('disable', false)) { + return + } + + const isLeaf = this._checkIsLeafNode(nodeData) + + this._trimSelectedNodes(nodeData) + + this.$emit('nodeclick', nodeData) + + if (this.isLocalData) { + if (isLeaf || !this._checkHasChildren(nodeData)) { + this.onFinish() + } + } else if (this.isCloudDataList) { + this.onFinish() + } else if (this.isCloudDataTree) { + if (isLeaf) { + this.onFinish() + } else if (!this._checkHasChildren(nodeData)) { + // 尝试请求一次,如果没有返回数据标记为叶子节点 + this.loadCloudDataNode(nodeData) + } + } + }, + + getChangeNodes(): Array { + const nodes: Array = [] + this.selectedNodes.forEach((node : UTSJSONObject) => { + const newNode: UTSJSONObject = {} + newNode[this.mappingTextName] = node.getString(this.mappingTextName) + newNode[this.mappingValueName] = node.getString(this.mappingValueName) + nodes.push(newNode) + }) + return nodes + }, + + onFinish() { }, + + // 加载数据(自动判定环境) + loadData() { + if (this.isLocalData) { + this.loadLocalData() + } else if (this.isCloudDataList) { + this.loadCloudDataList() + } else if (this.isCloudDataTree) { + this.loadCloudDataTree() + } + }, + + // 加载本地数据 + loadLocalData() { + this.treeData = this.localdata + if (Array.isArray(this.dataValue)) { + const value = this.dataValue as Array + this.selectedPaths = value.slice(0) + this._pushSelectedTreeNodes(value, this.localdata) + } else { + this._pushSelectedNodes(this.localdata) + } + }, + + // 加载 Cloud 数据 (单列) + loadCloudDataList() { + this._loadCloudData(null, (data : Array) => { + this.treeData = data + this._pushSelectedNodes(data) + }) + }, + + // 加载 Cloud 数据 (树形) + loadCloudDataTree() { + let commandOptions = { + field: this._cloudDataPostField(), + where: this._cloudDataTreeWhere(), + getTree: true + } as GetCommandOptions + if (this._checkIsNotNull(this.gettree)) { + commandOptions.startwith = `${this.selfField}=='${this.dataValue as string}'` + } + this._loadCloudData(commandOptions, (data : Array) => { + this.treeData = data + if (this.selectedPaths.length > 0) { + this._pushSelectedTreeNodes(this.selectedPaths, data) + } else { + this._pushSelectedNodes(data) + } + }) + }, + + // 加载 Cloud 数据 (节点) + loadCloudDataNode(nodeData : UTSJSONObject) { + const commandOptions = { + field: this._cloudDataPostField(), + where: this._cloudDataNodeWhere() + } as GetCommandOptions + this._loadCloudData(commandOptions, (data : Array) => { + nodeData['children'] = data + if (data.length == 0) { + nodeData['isleaf'] = true + this.onFinish() + } else { + this._pushSelectedNodes(data) + } + }) + }, + + // 回显 Cloud Tree Path + loadCloudDataPath() { + if (!this.hasCloudDataValue) { + return + } + + const command : GetCommandOptions = {} + + // 单列 + if (this.isCloudDataList) { + // 根据 field's as value标识匹配 where 条件 + let where : Array = []; + let whereField = this._getForeignKeyByField(); + if (whereField.length > 0) { + where.push(`${whereField} == '${this.dataValue as string}'`) + } + + let whereString = where.join(' || ') + if (this._checkIsNotNull(this.where)) { + whereString = `(${this.where}) && (${whereString})` + } + + command.field = this._cloudDataPostField() + command.where = whereString + } + + // 树形 + if (this.isCloudDataTree) { + command.field = this._cloudDataPostField() + command.getTreePath = { + startWith: `${this.selfField}=='${this.dataValue as string}'` + } + } + + this._loadCloudData(command, (data : Array) => { + this._extractTreePath(data, this.selectedPaths) + }) + }, + + _loadCloudData(options ?: GetCommandOptions, callback ?: ((data : Array) => void)) { + if (this.loading) { + return + } + this.loading = true + + this.error = null + + this._getCommand(options).then((response : UniCloudDBGetResult) => { + callback?.(response.data) + }).catch((err : any | null) => { + this.error = err as UniCloudError + }).finally(() => { + this.loading = false + }) + }, + + _cloudDataPostField() : string { + let fields = [this.field]; + if (this.parentField.length > 0) { + fields.push(`${this.parentField} as parent_value`) + } + return fields.join(',') + }, + + _cloudDataTreeWhere() : string { + let result : Array = [] + let selectedNodes = this.selectedNodes.length > 0 ? this.selectedNodes : this.selectedPaths + let parentField = this.parentField + if (parentField.length > 0) { + result.push(`${parentField} == null || ${parentField} == ""`) + } + if (selectedNodes.length > 0) { + for (var i = 0; i < selectedNodes.length - 1; i++) { + const parentFieldValue = selectedNodes[i].getString('value', '') + result.push(`${parentField} == '${parentFieldValue}'`) + } + } + + let where : Array = [] + if (this._checkIsNotNull(this.where)) { + where.push(`(${this.where as string})`) + } + + if (result.length > 0) { + where.push(`(${result.join(' || ')})`) + } + + return where.join(' && ') + }, + + _cloudDataNodeWhere() : string { + const where : Array = [] + if (this.selectedNodes.length > 0) { + const value = this.selectedNodes[this.selectedNodes.length - 1].getString('value', '') + where.push(`${this.parentField} == '${value}'`) + } + + let whereString = where.join(' || ') + if (this._checkIsNotNull(this.where)) { + return `(${this.where as string}) && (${whereString})` + } + + return whereString + }, + + _getWhereByForeignKey() : string { + let result : Array = [] + let whereField = this._getForeignKeyByField(); + if (whereField.length > 0) { + result.push(`${whereField} == '${this.dataValue as string}'`) + } + + if (this._checkIsNotNull(this.where)) { + return `(${this.where}) && (${result.join(' || ')})` + } + + return result.join(' || ') + }, + + _getForeignKeyByField() : string { + const fields = this.field.split(',') + let whereField = '' + for (let i = 0; i < fields.length; i++) { + const items = fields[i].split('as') + if (items.length < 2) { + continue + } + if (items[1].trim() === 'value') { + whereField = items[0].trim() + break + } + } + return whereField + }, + + _getCommand(options ?: GetCommandOptions) : Promise { + let db = uniCloud.databaseForJQL() + + let collection = Array.isArray(this.collection) ? db.collection(...(this.collection as Array)) : db.collection(this.collection) + + let filter : UniCloudDBFilter | null = null + if (this.foreignKey.length > 0) { + filter = collection.foreignKey(this.foreignKey) + } + + const where : any = options?.where ?? this.where + if (typeof where == 'string') { + const whereString = where as string + if (whereString.length > 0) { + filter = (filter != null) ? filter.where(where) : collection.where(where) + } + } else { + filter = (filter != null) ? filter.where(where) : collection.where(where) + } + + let query : UniCloudDBQuery | null = null + if (this.field.length > 0) { + query = (filter != null) ? filter.field(this.field) : collection.field(this.field) + } + if (this.groupby.length > 0) { + if (query != null) { + query = query.groupBy(this.groupby) + } else if (filter != null) { + query = filter.groupBy(this.groupby) + } + } + if (this.groupField.length > 0) { + if (query != null) { + query = query.groupField(this.groupField) + } else if (filter != null) { + query = filter.groupField(this.groupField) + } + } + if (this.distinct == true) { + if (query != null) { + query = query.distinct(this.field) + } else if (filter != null) { + query = filter.distinct(this.field) + } + } + if (this.orderby.length > 0) { + if (query != null) { + query = query.orderBy(this.orderby) + } else if (filter != null) { + query = filter.orderBy(this.orderby) + } + } + + const size = this.pagination.size + const current = this.pagination.current + if (query != null) { + query = query.skip(size * (current - 1)).limit(size) + } else if (filter != null) { + query = filter.skip(size * (current - 1)).limit(size) + } else { + query = collection.skip(size * (current - 1)).limit(size) + } + + const getOptions = {} + const treeOptions = { + limitLevel: this.limitlevel, + startWith: this.startwith + } + if (this.getcount == true) { + getOptions['getCount'] = this.getcount + } + + const getTree : any = options?.getTree ?? this.gettree + if (typeof getTree == 'string') { + const getTreeString = getTree as string + if (getTreeString.length > 0) { + getOptions['getTree'] = treeOptions + } + } else if (typeof getTree == 'object') { + getOptions['getTree'] = treeOptions + } else { + getOptions['getTree'] = getTree + } + + const getTreePath = options?.getTreePath ?? this.gettreepath + if (typeof getTreePath == 'string') { + const getTreePathString = getTreePath as string + if (getTreePathString.length > 0) { + getOptions['getTreePath'] = getTreePath + } + } else { + getOptions['getTreePath'] = getTreePath + } + + return query.get(getOptions) + }, + + _checkIsNotNull(value : any) : boolean { + if (typeof value == 'string') { + const valueString = value as string + return (valueString.length > 0) + } else if (value instanceof UTSJSONObject) { + return true + } + return false + }, + + _checkIsLeafNode(nodeData : UTSJSONObject) : boolean { + if (this.selectedIndex >= this.limitlevel) { + return true + } + + if (nodeData.getBoolean('isleaf', false)) { + return true + } + + return false + }, + + _checkHasChildren(nodeData : UTSJSONObject) : boolean { + const children = nodeData.getArray('children') ?? ([] as Array) + return children.length > 0 + }, + + _pushSelectedNodes(nodes : Array) { + this.selectedNodes.push(DefaultSelectedNode) + this.selectedPages.push(nodes) + this.selectedIndex = this.selectedPages.length - 1 + }, + + _trimSelectedNodes(nodeData : UTSJSONObject) { + this.selectedNodes.splice(this.selectedIndex) + this.selectedNodes.push(nodeData) + + if (this.selectedPages.length > 0) { + this.selectedPages.splice(this.selectedIndex + 1) + } + + const children = nodeData.getArray('children') ?? ([] as Array) + if (children.length > 0) { + this.selectedNodes.push(DefaultSelectedNode) + this.selectedPages.push(children) + } + + this.selectedIndex = this.selectedPages.length - 1 + }, + + _pushSelectedTreeNodes(paths : Array, nodes : Array) { + let children : Array = nodes + paths.forEach((node : UTSJSONObject) => { + const findNode = children.find((item : UTSJSONObject) : boolean => { + return (item.getString(this.mappingValueName) == node.getString(this.mappingValueName)) + }) + if (findNode != null) { + this.selectedPages.push(children) + this.selectedNodes.push(node) + children = findNode.getArray('children') ?? ([] as Array) + } + }) + this.selectedIndex = this.selectedPages.length - 1 + }, + + _extractTreePath(nodes : Array, result : Array) { + if (nodes.length == 0) { + return + } + + const node = nodes[0] + result.push(node) + + const children = node.getArray('children') + if (Array.isArray(children) && children!.length > 0) { + this._extractTreePath(children, result) + } + } + } +}) diff --git a/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.css b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.css new file mode 100644 index 00000000..39fe1c3a --- /dev/null +++ b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.css @@ -0,0 +1,76 @@ +.uni-data-pickerview { + position: relative; + flex-direction: column; + overflow: hidden; +} + +.loading-cover { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + align-items: center; + justify-content: center; + background-color: rgba(150, 150, 150, .1); +} + +.error { + background-color: #fff; + padding: 15px; +} + +.error-text { + color: #DD524D; +} + +.selected-node-list { + flex-direction: row; + flex-wrap: nowrap; +} + +.selected-node-item { + margin-left: 10px; + margin-right: 10px; + padding: 8px 10px 8px 10px; + border-bottom: 2px solid transparent; +} + +.selected-node-item-active { + color: #007aff; + border-bottom-color: #007aff; +} + +.list-view { + flex: 1; +} + +.list-item { + flex-direction: row; + justify-content: space-between; + padding: 12px 15px; + border-bottom: 1px solid #f0f0f0; +} + +.item-text { + color: #333333; +} + +.item-text-disabled { + opacity: .5; +} + +.item-text-overflow { + overflow: hidden; +} + +.check { + margin-right: 5px; + border: 2px solid #007aff; + border-left: 0; + border-top: 0; + height: 12px; + width: 6px; + transform-origin: center; + transform: rotate(45deg); +} diff --git a/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.uvue b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.uvue new file mode 100644 index 00000000..f4780f36 --- /dev/null +++ b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.uvue @@ -0,0 +1,69 @@ + + + + + diff --git a/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue new file mode 100644 index 00000000..6ebced92 --- /dev/null +++ b/smart-app/src/uni_modules/uni-data-picker/components/uni-data-pickerview/uni-data-pickerview.vue @@ -0,0 +1,323 @@ + + + + + diff --git a/smart-app/src/uni_modules/uni-data-picker/package.json b/smart-app/src/uni_modules/uni-data-picker/package.json new file mode 100644 index 00000000..a508162c --- /dev/null +++ b/smart-app/src/uni_modules/uni-data-picker/package.json @@ -0,0 +1,91 @@ +{ + "id": "uni-data-picker", + "displayName": "uni-data-picker 数据驱动的picker选择器", + "version": "2.0.0", + "description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景", + "keywords": [ + "uni-ui", + "uniui", + "picker", + "级联", + "省市区", + "" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [ + "uni-load-more", + "uni-icons", + "uni-scss" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y", + "app-uvue": "y" + }, + "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", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/smart-app/src/uni_modules/uni-data-picker/readme.md b/smart-app/src/uni_modules/uni-data-picker/readme.md new file mode 100644 index 00000000..19dd0e83 --- /dev/null +++ b/smart-app/src/uni_modules/uni-data-picker/readme.md @@ -0,0 +1,22 @@ +## DataPicker 级联选择 +> **组件名:uni-data-picker** +> 代码块: `uDataPicker` +> 关联组件:`uni-data-pickerview`、`uni-load-more`。 + + +`` 是一个选择类[datacom组件](https://uniapp.dcloud.net.cn/component/datacom)。 + +支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。 + +候选数据支持一次性加载完毕,也支持懒加载,比如示例图中,选择了“北京”后,动态加载北京的区县数据。 + +`` 组件尤其适用于地址选择、分类选择等选择类。 + +`` 支持本地数据、云端静态数据(json),uniCloud云数据库数据。 + +`` 可以通过JQL直连uniCloud云数据库,配套[DB Schema](https://uniapp.dcloud.net.cn/uniCloud/schema),可在schema2code中自动生成前端页面,还支持服务器端校验。 + +在uniCloud数据表中新建表“uni-id-address”和“opendb-city-china”,这2个表的schema自带foreignKey关联。在“uni-id-address”表的表结构页面使用schema2code生成前端页面,会自动生成地址管理的维护页面,自动从“opendb-city-china”表包含的中国所有省市区信息里选择地址。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-picker) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-icons/changelog.md b/smart-app/src/uni_modules/uni-icons/changelog.md new file mode 100644 index 00000000..620ab027 --- /dev/null +++ b/smart-app/src/uni_modules/uni-icons/changelog.md @@ -0,0 +1,40 @@ +## 2.0.9(2024-01-12) +fix: 修复图标大小默认值错误的问题 +## 2.0.8(2023-12-14) +- 修复 项目未使用 ts 情况下,打包报错的bug +## 2.0.7(2023-12-14) +- 修复 size 属性为 string 时,不加单位导致尺寸异常的bug +## 2.0.6(2023-12-11) +- 优化 兼容老版本icon类型,如 top ,bottom 等 +## 2.0.5(2023-12-11) +- 优化 兼容老版本icon类型,如 top ,bottom 等 +## 2.0.4(2023-12-06) +- 优化 uni-app x 下示例项目图标排序 +## 2.0.3(2023-12-06) +- 修复 nvue下引入组件报错的bug +## 2.0.2(2023-12-05) +-优化 size 属性支持单位 +## 2.0.1(2023-12-05) +- 新增 uni-app x 支持定义图标 +## 1.3.5(2022-01-24) +- 优化 size 属性可以传入不带单位的字符串数值 +## 1.3.4(2022-01-24) +- 优化 size 支持其他单位 +## 1.3.3(2022-01-17) +- 修复 nvue 有些图标不显示的bug,兼容老版本图标 +## 1.3.2(2021-12-01) +- 优化 示例可复制图标名称 +## 1.3.1(2021-11-23) +- 优化 兼容旧组件 type 值 +## 1.3.0(2021-11-19) +- 新增 更多图标 +- 优化 自定义图标使用方式 +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-icons](https://uniapp.dcloud.io/component/uniui/uni-icons) +## 1.1.7(2021-11-08) +## 1.2.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.5(2021-05-12) +- 新增 组件示例地址 +## 1.1.4(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/smart-app/src/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue b/smart-app/src/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue new file mode 100644 index 00000000..398678ee --- /dev/null +++ b/smart-app/src/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue @@ -0,0 +1,91 @@ + + + + + diff --git a/smart-app/src/uni_modules/uni-icons/components/uni-icons/uni-icons.vue b/smart-app/src/uni_modules/uni-icons/components/uni-icons/uni-icons.vue new file mode 100644 index 00000000..7da53560 --- /dev/null +++ b/smart-app/src/uni_modules/uni-icons/components/uni-icons/uni-icons.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/smart-app/src/uni_modules/uni-icons/components/uni-icons/uniicons.css b/smart-app/src/uni_modules/uni-icons/components/uni-icons/uniicons.css new file mode 100644 index 00000000..0a6b6fea --- /dev/null +++ b/smart-app/src/uni_modules/uni-icons/components/uni-icons/uniicons.css @@ -0,0 +1,664 @@ + +.uniui-cart-filled:before { + content: "\e6d0"; +} + +.uniui-gift-filled:before { + content: "\e6c4"; +} + +.uniui-color:before { + content: "\e6cf"; +} + +.uniui-wallet:before { + content: "\e6b1"; +} + +.uniui-settings-filled:before { + content: "\e6ce"; +} + +.uniui-auth-filled:before { + content: "\e6cc"; +} + +.uniui-shop-filled:before { + content: "\e6cd"; +} + +.uniui-staff-filled:before { + content: "\e6cb"; +} + +.uniui-vip-filled:before { + content: "\e6c6"; +} + +.uniui-plus-filled:before { + content: "\e6c7"; +} + +.uniui-folder-add-filled:before { + content: "\e6c8"; +} + +.uniui-color-filled:before { + content: "\e6c9"; +} + +.uniui-tune-filled:before { + content: "\e6ca"; +} + +.uniui-calendar-filled:before { + content: "\e6c0"; +} + +.uniui-notification-filled:before { + content: "\e6c1"; +} + +.uniui-wallet-filled:before { + content: "\e6c2"; +} + +.uniui-medal-filled:before { + content: "\e6c3"; +} + +.uniui-fire-filled:before { + content: "\e6c5"; +} + +.uniui-refreshempty:before { + content: "\e6bf"; +} + +.uniui-location-filled:before { + content: "\e6af"; +} + +.uniui-person-filled:before { + content: "\e69d"; +} + +.uniui-personadd-filled:before { + content: "\e698"; +} + +.uniui-arrowthinleft:before { + content: "\e6d2"; +} + +.uniui-arrowthinup:before { + content: "\e6d3"; +} + +.uniui-arrowthindown:before { + content: "\e6d4"; +} + +.uniui-back:before { + content: "\e6b9"; +} + +.uniui-forward:before { + content: "\e6ba"; +} + +.uniui-arrow-right:before { + content: "\e6bb"; +} + +.uniui-arrow-left:before { + content: "\e6bc"; +} + +.uniui-arrow-up:before { + content: "\e6bd"; +} + +.uniui-arrow-down:before { + content: "\e6be"; +} + +.uniui-arrowthinright:before { + content: "\e6d1"; +} + +.uniui-down:before { + content: "\e6b8"; +} + +.uniui-bottom:before { + content: "\e6b8"; +} + +.uniui-arrowright:before { + content: "\e6d5"; +} + +.uniui-right:before { + content: "\e6b5"; +} + +.uniui-up:before { + content: "\e6b6"; +} + +.uniui-top:before { + content: "\e6b6"; +} + +.uniui-left:before { + content: "\e6b7"; +} + +.uniui-arrowup:before { + content: "\e6d6"; +} + +.uniui-eye:before { + content: "\e651"; +} + +.uniui-eye-filled:before { + content: "\e66a"; +} + +.uniui-eye-slash:before { + content: "\e6b3"; +} + +.uniui-eye-slash-filled:before { + content: "\e6b4"; +} + +.uniui-info-filled:before { + content: "\e649"; +} + +.uniui-reload:before { + content: "\e6b2"; +} + +.uniui-micoff-filled:before { + content: "\e6b0"; +} + +.uniui-map-pin-ellipse:before { + content: "\e6ac"; +} + +.uniui-map-pin:before { + content: "\e6ad"; +} + +.uniui-location:before { + content: "\e6ae"; +} + +.uniui-starhalf:before { + content: "\e683"; +} + +.uniui-star:before { + content: "\e688"; +} + +.uniui-star-filled:before { + content: "\e68f"; +} + +.uniui-calendar:before { + content: "\e6a0"; +} + +.uniui-fire:before { + content: "\e6a1"; +} + +.uniui-medal:before { + content: "\e6a2"; +} + +.uniui-font:before { + content: "\e6a3"; +} + +.uniui-gift:before { + content: "\e6a4"; +} + +.uniui-link:before { + content: "\e6a5"; +} + +.uniui-notification:before { + content: "\e6a6"; +} + +.uniui-staff:before { + content: "\e6a7"; +} + +.uniui-vip:before { + content: "\e6a8"; +} + +.uniui-folder-add:before { + content: "\e6a9"; +} + +.uniui-tune:before { + content: "\e6aa"; +} + +.uniui-auth:before { + content: "\e6ab"; +} + +.uniui-person:before { + content: "\e699"; +} + +.uniui-email-filled:before { + content: "\e69a"; +} + +.uniui-phone-filled:before { + content: "\e69b"; +} + +.uniui-phone:before { + content: "\e69c"; +} + +.uniui-email:before { + content: "\e69e"; +} + +.uniui-personadd:before { + content: "\e69f"; +} + +.uniui-chatboxes-filled:before { + content: "\e692"; +} + +.uniui-contact:before { + content: "\e693"; +} + +.uniui-chatbubble-filled:before { + content: "\e694"; +} + +.uniui-contact-filled:before { + content: "\e695"; +} + +.uniui-chatboxes:before { + content: "\e696"; +} + +.uniui-chatbubble:before { + content: "\e697"; +} + +.uniui-upload-filled:before { + content: "\e68e"; +} + +.uniui-upload:before { + content: "\e690"; +} + +.uniui-weixin:before { + content: "\e691"; +} + +.uniui-compose:before { + content: "\e67f"; +} + +.uniui-qq:before { + content: "\e680"; +} + +.uniui-download-filled:before { + content: "\e681"; +} + +.uniui-pyq:before { + content: "\e682"; +} + +.uniui-sound:before { + content: "\e684"; +} + +.uniui-trash-filled:before { + content: "\e685"; +} + +.uniui-sound-filled:before { + content: "\e686"; +} + +.uniui-trash:before { + content: "\e687"; +} + +.uniui-videocam-filled:before { + content: "\e689"; +} + +.uniui-spinner-cycle:before { + content: "\e68a"; +} + +.uniui-weibo:before { + content: "\e68b"; +} + +.uniui-videocam:before { + content: "\e68c"; +} + +.uniui-download:before { + content: "\e68d"; +} + +.uniui-help:before { + content: "\e679"; +} + +.uniui-navigate-filled:before { + content: "\e67a"; +} + +.uniui-plusempty:before { + content: "\e67b"; +} + +.uniui-smallcircle:before { + content: "\e67c"; +} + +.uniui-minus-filled:before { + content: "\e67d"; +} + +.uniui-micoff:before { + content: "\e67e"; +} + +.uniui-closeempty:before { + content: "\e66c"; +} + +.uniui-clear:before { + content: "\e66d"; +} + +.uniui-navigate:before { + content: "\e66e"; +} + +.uniui-minus:before { + content: "\e66f"; +} + +.uniui-image:before { + content: "\e670"; +} + +.uniui-mic:before { + content: "\e671"; +} + +.uniui-paperplane:before { + content: "\e672"; +} + +.uniui-close:before { + content: "\e673"; +} + +.uniui-help-filled:before { + content: "\e674"; +} + +.uniui-paperplane-filled:before { + content: "\e675"; +} + +.uniui-plus:before { + content: "\e676"; +} + +.uniui-mic-filled:before { + content: "\e677"; +} + +.uniui-image-filled:before { + content: "\e678"; +} + +.uniui-locked-filled:before { + content: "\e668"; +} + +.uniui-info:before { + content: "\e669"; +} + +.uniui-locked:before { + content: "\e66b"; +} + +.uniui-camera-filled:before { + content: "\e658"; +} + +.uniui-chat-filled:before { + content: "\e659"; +} + +.uniui-camera:before { + content: "\e65a"; +} + +.uniui-circle:before { + content: "\e65b"; +} + +.uniui-checkmarkempty:before { + content: "\e65c"; +} + +.uniui-chat:before { + content: "\e65d"; +} + +.uniui-circle-filled:before { + content: "\e65e"; +} + +.uniui-flag:before { + content: "\e65f"; +} + +.uniui-flag-filled:before { + content: "\e660"; +} + +.uniui-gear-filled:before { + content: "\e661"; +} + +.uniui-home:before { + content: "\e662"; +} + +.uniui-home-filled:before { + content: "\e663"; +} + +.uniui-gear:before { + content: "\e664"; +} + +.uniui-smallcircle-filled:before { + content: "\e665"; +} + +.uniui-map-filled:before { + content: "\e666"; +} + +.uniui-map:before { + content: "\e667"; +} + +.uniui-refresh-filled:before { + content: "\e656"; +} + +.uniui-refresh:before { + content: "\e657"; +} + +.uniui-cloud-upload:before { + content: "\e645"; +} + +.uniui-cloud-download-filled:before { + content: "\e646"; +} + +.uniui-cloud-download:before { + content: "\e647"; +} + +.uniui-cloud-upload-filled:before { + content: "\e648"; +} + +.uniui-redo:before { + content: "\e64a"; +} + +.uniui-images-filled:before { + content: "\e64b"; +} + +.uniui-undo-filled:before { + content: "\e64c"; +} + +.uniui-more:before { + content: "\e64d"; +} + +.uniui-more-filled:before { + content: "\e64e"; +} + +.uniui-undo:before { + content: "\e64f"; +} + +.uniui-images:before { + content: "\e650"; +} + +.uniui-paperclip:before { + content: "\e652"; +} + +.uniui-settings:before { + content: "\e653"; +} + +.uniui-search:before { + content: "\e654"; +} + +.uniui-redo-filled:before { + content: "\e655"; +} + +.uniui-list:before { + content: "\e644"; +} + +.uniui-mail-open-filled:before { + content: "\e63a"; +} + +.uniui-hand-down-filled:before { + content: "\e63c"; +} + +.uniui-hand-down:before { + content: "\e63d"; +} + +.uniui-hand-up-filled:before { + content: "\e63e"; +} + +.uniui-hand-up:before { + content: "\e63f"; +} + +.uniui-heart-filled:before { + content: "\e641"; +} + +.uniui-mail-open:before { + content: "\e643"; +} + +.uniui-heart:before { + content: "\e639"; +} + +.uniui-loop:before { + content: "\e633"; +} + +.uniui-pulldown:before { + content: "\e632"; +} + +.uniui-scan:before { + content: "\e62a"; +} + +.uniui-bars:before { + content: "\e627"; +} + +.uniui-checkbox:before { + content: "\e62b"; +} + +.uniui-checkbox-filled:before { + content: "\e62c"; +} + +.uniui-shop:before { + content: "\e62f"; +} + +.uniui-headphones:before { + content: "\e630"; +} + +.uniui-cart:before { + content: "\e631"; +} diff --git a/smart-app/src/uni_modules/uni-icons/components/uni-icons/uniicons.ttf b/smart-app/src/uni_modules/uni-icons/components/uni-icons/uniicons.ttf new file mode 100644 index 00000000..14696d03 Binary files /dev/null and b/smart-app/src/uni_modules/uni-icons/components/uni-icons/uniicons.ttf differ diff --git a/smart-app/src/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts b/smart-app/src/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts new file mode 100644 index 00000000..98e93aa0 --- /dev/null +++ b/smart-app/src/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts @@ -0,0 +1,664 @@ + +export type IconsData = { + id : string + name : string + font_family : string + css_prefix_text : string + description : string + glyphs : Array +} + +export type IconsDataItem = { + font_class : string + unicode : string +} + + +export const fontData = [ + { + "font_class": "arrow-down", + "unicode": "\ue6be" + }, + { + "font_class": "arrow-left", + "unicode": "\ue6bc" + }, + { + "font_class": "arrow-right", + "unicode": "\ue6bb" + }, + { + "font_class": "arrow-up", + "unicode": "\ue6bd" + }, + { + "font_class": "auth", + "unicode": "\ue6ab" + }, + { + "font_class": "auth-filled", + "unicode": "\ue6cc" + }, + { + "font_class": "back", + "unicode": "\ue6b9" + }, + { + "font_class": "bars", + "unicode": "\ue627" + }, + { + "font_class": "calendar", + "unicode": "\ue6a0" + }, + { + "font_class": "calendar-filled", + "unicode": "\ue6c0" + }, + { + "font_class": "camera", + "unicode": "\ue65a" + }, + { + "font_class": "camera-filled", + "unicode": "\ue658" + }, + { + "font_class": "cart", + "unicode": "\ue631" + }, + { + "font_class": "cart-filled", + "unicode": "\ue6d0" + }, + { + "font_class": "chat", + "unicode": "\ue65d" + }, + { + "font_class": "chat-filled", + "unicode": "\ue659" + }, + { + "font_class": "chatboxes", + "unicode": "\ue696" + }, + { + "font_class": "chatboxes-filled", + "unicode": "\ue692" + }, + { + "font_class": "chatbubble", + "unicode": "\ue697" + }, + { + "font_class": "chatbubble-filled", + "unicode": "\ue694" + }, + { + "font_class": "checkbox", + "unicode": "\ue62b" + }, + { + "font_class": "checkbox-filled", + "unicode": "\ue62c" + }, + { + "font_class": "checkmarkempty", + "unicode": "\ue65c" + }, + { + "font_class": "circle", + "unicode": "\ue65b" + }, + { + "font_class": "circle-filled", + "unicode": "\ue65e" + }, + { + "font_class": "clear", + "unicode": "\ue66d" + }, + { + "font_class": "close", + "unicode": "\ue673" + }, + { + "font_class": "closeempty", + "unicode": "\ue66c" + }, + { + "font_class": "cloud-download", + "unicode": "\ue647" + }, + { + "font_class": "cloud-download-filled", + "unicode": "\ue646" + }, + { + "font_class": "cloud-upload", + "unicode": "\ue645" + }, + { + "font_class": "cloud-upload-filled", + "unicode": "\ue648" + }, + { + "font_class": "color", + "unicode": "\ue6cf" + }, + { + "font_class": "color-filled", + "unicode": "\ue6c9" + }, + { + "font_class": "compose", + "unicode": "\ue67f" + }, + { + "font_class": "contact", + "unicode": "\ue693" + }, + { + "font_class": "contact-filled", + "unicode": "\ue695" + }, + { + "font_class": "down", + "unicode": "\ue6b8" + }, + { + "font_class": "bottom", + "unicode": "\ue6b8" + }, + { + "font_class": "download", + "unicode": "\ue68d" + }, + { + "font_class": "download-filled", + "unicode": "\ue681" + }, + { + "font_class": "email", + "unicode": "\ue69e" + }, + { + "font_class": "email-filled", + "unicode": "\ue69a" + }, + { + "font_class": "eye", + "unicode": "\ue651" + }, + { + "font_class": "eye-filled", + "unicode": "\ue66a" + }, + { + "font_class": "eye-slash", + "unicode": "\ue6b3" + }, + { + "font_class": "eye-slash-filled", + "unicode": "\ue6b4" + }, + { + "font_class": "fire", + "unicode": "\ue6a1" + }, + { + "font_class": "fire-filled", + "unicode": "\ue6c5" + }, + { + "font_class": "flag", + "unicode": "\ue65f" + }, + { + "font_class": "flag-filled", + "unicode": "\ue660" + }, + { + "font_class": "folder-add", + "unicode": "\ue6a9" + }, + { + "font_class": "folder-add-filled", + "unicode": "\ue6c8" + }, + { + "font_class": "font", + "unicode": "\ue6a3" + }, + { + "font_class": "forward", + "unicode": "\ue6ba" + }, + { + "font_class": "gear", + "unicode": "\ue664" + }, + { + "font_class": "gear-filled", + "unicode": "\ue661" + }, + { + "font_class": "gift", + "unicode": "\ue6a4" + }, + { + "font_class": "gift-filled", + "unicode": "\ue6c4" + }, + { + "font_class": "hand-down", + "unicode": "\ue63d" + }, + { + "font_class": "hand-down-filled", + "unicode": "\ue63c" + }, + { + "font_class": "hand-up", + "unicode": "\ue63f" + }, + { + "font_class": "hand-up-filled", + "unicode": "\ue63e" + }, + { + "font_class": "headphones", + "unicode": "\ue630" + }, + { + "font_class": "heart", + "unicode": "\ue639" + }, + { + "font_class": "heart-filled", + "unicode": "\ue641" + }, + { + "font_class": "help", + "unicode": "\ue679" + }, + { + "font_class": "help-filled", + "unicode": "\ue674" + }, + { + "font_class": "home", + "unicode": "\ue662" + }, + { + "font_class": "home-filled", + "unicode": "\ue663" + }, + { + "font_class": "image", + "unicode": "\ue670" + }, + { + "font_class": "image-filled", + "unicode": "\ue678" + }, + { + "font_class": "images", + "unicode": "\ue650" + }, + { + "font_class": "images-filled", + "unicode": "\ue64b" + }, + { + "font_class": "info", + "unicode": "\ue669" + }, + { + "font_class": "info-filled", + "unicode": "\ue649" + }, + { + "font_class": "left", + "unicode": "\ue6b7" + }, + { + "font_class": "link", + "unicode": "\ue6a5" + }, + { + "font_class": "list", + "unicode": "\ue644" + }, + { + "font_class": "location", + "unicode": "\ue6ae" + }, + { + "font_class": "location-filled", + "unicode": "\ue6af" + }, + { + "font_class": "locked", + "unicode": "\ue66b" + }, + { + "font_class": "locked-filled", + "unicode": "\ue668" + }, + { + "font_class": "loop", + "unicode": "\ue633" + }, + { + "font_class": "mail-open", + "unicode": "\ue643" + }, + { + "font_class": "mail-open-filled", + "unicode": "\ue63a" + }, + { + "font_class": "map", + "unicode": "\ue667" + }, + { + "font_class": "map-filled", + "unicode": "\ue666" + }, + { + "font_class": "map-pin", + "unicode": "\ue6ad" + }, + { + "font_class": "map-pin-ellipse", + "unicode": "\ue6ac" + }, + { + "font_class": "medal", + "unicode": "\ue6a2" + }, + { + "font_class": "medal-filled", + "unicode": "\ue6c3" + }, + { + "font_class": "mic", + "unicode": "\ue671" + }, + { + "font_class": "mic-filled", + "unicode": "\ue677" + }, + { + "font_class": "micoff", + "unicode": "\ue67e" + }, + { + "font_class": "micoff-filled", + "unicode": "\ue6b0" + }, + { + "font_class": "minus", + "unicode": "\ue66f" + }, + { + "font_class": "minus-filled", + "unicode": "\ue67d" + }, + { + "font_class": "more", + "unicode": "\ue64d" + }, + { + "font_class": "more-filled", + "unicode": "\ue64e" + }, + { + "font_class": "navigate", + "unicode": "\ue66e" + }, + { + "font_class": "navigate-filled", + "unicode": "\ue67a" + }, + { + "font_class": "notification", + "unicode": "\ue6a6" + }, + { + "font_class": "notification-filled", + "unicode": "\ue6c1" + }, + { + "font_class": "paperclip", + "unicode": "\ue652" + }, + { + "font_class": "paperplane", + "unicode": "\ue672" + }, + { + "font_class": "paperplane-filled", + "unicode": "\ue675" + }, + { + "font_class": "person", + "unicode": "\ue699" + }, + { + "font_class": "person-filled", + "unicode": "\ue69d" + }, + { + "font_class": "personadd", + "unicode": "\ue69f" + }, + { + "font_class": "personadd-filled", + "unicode": "\ue698" + }, + { + "font_class": "personadd-filled-copy", + "unicode": "\ue6d1" + }, + { + "font_class": "phone", + "unicode": "\ue69c" + }, + { + "font_class": "phone-filled", + "unicode": "\ue69b" + }, + { + "font_class": "plus", + "unicode": "\ue676" + }, + { + "font_class": "plus-filled", + "unicode": "\ue6c7" + }, + { + "font_class": "plusempty", + "unicode": "\ue67b" + }, + { + "font_class": "pulldown", + "unicode": "\ue632" + }, + { + "font_class": "pyq", + "unicode": "\ue682" + }, + { + "font_class": "qq", + "unicode": "\ue680" + }, + { + "font_class": "redo", + "unicode": "\ue64a" + }, + { + "font_class": "redo-filled", + "unicode": "\ue655" + }, + { + "font_class": "refresh", + "unicode": "\ue657" + }, + { + "font_class": "refresh-filled", + "unicode": "\ue656" + }, + { + "font_class": "refreshempty", + "unicode": "\ue6bf" + }, + { + "font_class": "reload", + "unicode": "\ue6b2" + }, + { + "font_class": "right", + "unicode": "\ue6b5" + }, + { + "font_class": "scan", + "unicode": "\ue62a" + }, + { + "font_class": "search", + "unicode": "\ue654" + }, + { + "font_class": "settings", + "unicode": "\ue653" + }, + { + "font_class": "settings-filled", + "unicode": "\ue6ce" + }, + { + "font_class": "shop", + "unicode": "\ue62f" + }, + { + "font_class": "shop-filled", + "unicode": "\ue6cd" + }, + { + "font_class": "smallcircle", + "unicode": "\ue67c" + }, + { + "font_class": "smallcircle-filled", + "unicode": "\ue665" + }, + { + "font_class": "sound", + "unicode": "\ue684" + }, + { + "font_class": "sound-filled", + "unicode": "\ue686" + }, + { + "font_class": "spinner-cycle", + "unicode": "\ue68a" + }, + { + "font_class": "staff", + "unicode": "\ue6a7" + }, + { + "font_class": "staff-filled", + "unicode": "\ue6cb" + }, + { + "font_class": "star", + "unicode": "\ue688" + }, + { + "font_class": "star-filled", + "unicode": "\ue68f" + }, + { + "font_class": "starhalf", + "unicode": "\ue683" + }, + { + "font_class": "trash", + "unicode": "\ue687" + }, + { + "font_class": "trash-filled", + "unicode": "\ue685" + }, + { + "font_class": "tune", + "unicode": "\ue6aa" + }, + { + "font_class": "tune-filled", + "unicode": "\ue6ca" + }, + { + "font_class": "undo", + "unicode": "\ue64f" + }, + { + "font_class": "undo-filled", + "unicode": "\ue64c" + }, + { + "font_class": "up", + "unicode": "\ue6b6" + }, + { + "font_class": "top", + "unicode": "\ue6b6" + }, + { + "font_class": "upload", + "unicode": "\ue690" + }, + { + "font_class": "upload-filled", + "unicode": "\ue68e" + }, + { + "font_class": "videocam", + "unicode": "\ue68c" + }, + { + "font_class": "videocam-filled", + "unicode": "\ue689" + }, + { + "font_class": "vip", + "unicode": "\ue6a8" + }, + { + "font_class": "vip-filled", + "unicode": "\ue6c6" + }, + { + "font_class": "wallet", + "unicode": "\ue6b1" + }, + { + "font_class": "wallet-filled", + "unicode": "\ue6c2" + }, + { + "font_class": "weibo", + "unicode": "\ue68b" + }, + { + "font_class": "weixin", + "unicode": "\ue691" + } +] as IconsDataItem[] + +// export const fontData = JSON.parse(fontDataJson) diff --git a/smart-app/src/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js b/smart-app/src/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js new file mode 100644 index 00000000..1cd11e15 --- /dev/null +++ b/smart-app/src/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js @@ -0,0 +1,649 @@ + +export const fontData = [ + { + "font_class": "arrow-down", + "unicode": "\ue6be" + }, + { + "font_class": "arrow-left", + "unicode": "\ue6bc" + }, + { + "font_class": "arrow-right", + "unicode": "\ue6bb" + }, + { + "font_class": "arrow-up", + "unicode": "\ue6bd" + }, + { + "font_class": "auth", + "unicode": "\ue6ab" + }, + { + "font_class": "auth-filled", + "unicode": "\ue6cc" + }, + { + "font_class": "back", + "unicode": "\ue6b9" + }, + { + "font_class": "bars", + "unicode": "\ue627" + }, + { + "font_class": "calendar", + "unicode": "\ue6a0" + }, + { + "font_class": "calendar-filled", + "unicode": "\ue6c0" + }, + { + "font_class": "camera", + "unicode": "\ue65a" + }, + { + "font_class": "camera-filled", + "unicode": "\ue658" + }, + { + "font_class": "cart", + "unicode": "\ue631" + }, + { + "font_class": "cart-filled", + "unicode": "\ue6d0" + }, + { + "font_class": "chat", + "unicode": "\ue65d" + }, + { + "font_class": "chat-filled", + "unicode": "\ue659" + }, + { + "font_class": "chatboxes", + "unicode": "\ue696" + }, + { + "font_class": "chatboxes-filled", + "unicode": "\ue692" + }, + { + "font_class": "chatbubble", + "unicode": "\ue697" + }, + { + "font_class": "chatbubble-filled", + "unicode": "\ue694" + }, + { + "font_class": "checkbox", + "unicode": "\ue62b" + }, + { + "font_class": "checkbox-filled", + "unicode": "\ue62c" + }, + { + "font_class": "checkmarkempty", + "unicode": "\ue65c" + }, + { + "font_class": "circle", + "unicode": "\ue65b" + }, + { + "font_class": "circle-filled", + "unicode": "\ue65e" + }, + { + "font_class": "clear", + "unicode": "\ue66d" + }, + { + "font_class": "close", + "unicode": "\ue673" + }, + { + "font_class": "closeempty", + "unicode": "\ue66c" + }, + { + "font_class": "cloud-download", + "unicode": "\ue647" + }, + { + "font_class": "cloud-download-filled", + "unicode": "\ue646" + }, + { + "font_class": "cloud-upload", + "unicode": "\ue645" + }, + { + "font_class": "cloud-upload-filled", + "unicode": "\ue648" + }, + { + "font_class": "color", + "unicode": "\ue6cf" + }, + { + "font_class": "color-filled", + "unicode": "\ue6c9" + }, + { + "font_class": "compose", + "unicode": "\ue67f" + }, + { + "font_class": "contact", + "unicode": "\ue693" + }, + { + "font_class": "contact-filled", + "unicode": "\ue695" + }, + { + "font_class": "down", + "unicode": "\ue6b8" + }, + { + "font_class": "bottom", + "unicode": "\ue6b8" + }, + { + "font_class": "download", + "unicode": "\ue68d" + }, + { + "font_class": "download-filled", + "unicode": "\ue681" + }, + { + "font_class": "email", + "unicode": "\ue69e" + }, + { + "font_class": "email-filled", + "unicode": "\ue69a" + }, + { + "font_class": "eye", + "unicode": "\ue651" + }, + { + "font_class": "eye-filled", + "unicode": "\ue66a" + }, + { + "font_class": "eye-slash", + "unicode": "\ue6b3" + }, + { + "font_class": "eye-slash-filled", + "unicode": "\ue6b4" + }, + { + "font_class": "fire", + "unicode": "\ue6a1" + }, + { + "font_class": "fire-filled", + "unicode": "\ue6c5" + }, + { + "font_class": "flag", + "unicode": "\ue65f" + }, + { + "font_class": "flag-filled", + "unicode": "\ue660" + }, + { + "font_class": "folder-add", + "unicode": "\ue6a9" + }, + { + "font_class": "folder-add-filled", + "unicode": "\ue6c8" + }, + { + "font_class": "font", + "unicode": "\ue6a3" + }, + { + "font_class": "forward", + "unicode": "\ue6ba" + }, + { + "font_class": "gear", + "unicode": "\ue664" + }, + { + "font_class": "gear-filled", + "unicode": "\ue661" + }, + { + "font_class": "gift", + "unicode": "\ue6a4" + }, + { + "font_class": "gift-filled", + "unicode": "\ue6c4" + }, + { + "font_class": "hand-down", + "unicode": "\ue63d" + }, + { + "font_class": "hand-down-filled", + "unicode": "\ue63c" + }, + { + "font_class": "hand-up", + "unicode": "\ue63f" + }, + { + "font_class": "hand-up-filled", + "unicode": "\ue63e" + }, + { + "font_class": "headphones", + "unicode": "\ue630" + }, + { + "font_class": "heart", + "unicode": "\ue639" + }, + { + "font_class": "heart-filled", + "unicode": "\ue641" + }, + { + "font_class": "help", + "unicode": "\ue679" + }, + { + "font_class": "help-filled", + "unicode": "\ue674" + }, + { + "font_class": "home", + "unicode": "\ue662" + }, + { + "font_class": "home-filled", + "unicode": "\ue663" + }, + { + "font_class": "image", + "unicode": "\ue670" + }, + { + "font_class": "image-filled", + "unicode": "\ue678" + }, + { + "font_class": "images", + "unicode": "\ue650" + }, + { + "font_class": "images-filled", + "unicode": "\ue64b" + }, + { + "font_class": "info", + "unicode": "\ue669" + }, + { + "font_class": "info-filled", + "unicode": "\ue649" + }, + { + "font_class": "left", + "unicode": "\ue6b7" + }, + { + "font_class": "link", + "unicode": "\ue6a5" + }, + { + "font_class": "list", + "unicode": "\ue644" + }, + { + "font_class": "location", + "unicode": "\ue6ae" + }, + { + "font_class": "location-filled", + "unicode": "\ue6af" + }, + { + "font_class": "locked", + "unicode": "\ue66b" + }, + { + "font_class": "locked-filled", + "unicode": "\ue668" + }, + { + "font_class": "loop", + "unicode": "\ue633" + }, + { + "font_class": "mail-open", + "unicode": "\ue643" + }, + { + "font_class": "mail-open-filled", + "unicode": "\ue63a" + }, + { + "font_class": "map", + "unicode": "\ue667" + }, + { + "font_class": "map-filled", + "unicode": "\ue666" + }, + { + "font_class": "map-pin", + "unicode": "\ue6ad" + }, + { + "font_class": "map-pin-ellipse", + "unicode": "\ue6ac" + }, + { + "font_class": "medal", + "unicode": "\ue6a2" + }, + { + "font_class": "medal-filled", + "unicode": "\ue6c3" + }, + { + "font_class": "mic", + "unicode": "\ue671" + }, + { + "font_class": "mic-filled", + "unicode": "\ue677" + }, + { + "font_class": "micoff", + "unicode": "\ue67e" + }, + { + "font_class": "micoff-filled", + "unicode": "\ue6b0" + }, + { + "font_class": "minus", + "unicode": "\ue66f" + }, + { + "font_class": "minus-filled", + "unicode": "\ue67d" + }, + { + "font_class": "more", + "unicode": "\ue64d" + }, + { + "font_class": "more-filled", + "unicode": "\ue64e" + }, + { + "font_class": "navigate", + "unicode": "\ue66e" + }, + { + "font_class": "navigate-filled", + "unicode": "\ue67a" + }, + { + "font_class": "notification", + "unicode": "\ue6a6" + }, + { + "font_class": "notification-filled", + "unicode": "\ue6c1" + }, + { + "font_class": "paperclip", + "unicode": "\ue652" + }, + { + "font_class": "paperplane", + "unicode": "\ue672" + }, + { + "font_class": "paperplane-filled", + "unicode": "\ue675" + }, + { + "font_class": "person", + "unicode": "\ue699" + }, + { + "font_class": "person-filled", + "unicode": "\ue69d" + }, + { + "font_class": "personadd", + "unicode": "\ue69f" + }, + { + "font_class": "personadd-filled", + "unicode": "\ue698" + }, + { + "font_class": "personadd-filled-copy", + "unicode": "\ue6d1" + }, + { + "font_class": "phone", + "unicode": "\ue69c" + }, + { + "font_class": "phone-filled", + "unicode": "\ue69b" + }, + { + "font_class": "plus", + "unicode": "\ue676" + }, + { + "font_class": "plus-filled", + "unicode": "\ue6c7" + }, + { + "font_class": "plusempty", + "unicode": "\ue67b" + }, + { + "font_class": "pulldown", + "unicode": "\ue632" + }, + { + "font_class": "pyq", + "unicode": "\ue682" + }, + { + "font_class": "qq", + "unicode": "\ue680" + }, + { + "font_class": "redo", + "unicode": "\ue64a" + }, + { + "font_class": "redo-filled", + "unicode": "\ue655" + }, + { + "font_class": "refresh", + "unicode": "\ue657" + }, + { + "font_class": "refresh-filled", + "unicode": "\ue656" + }, + { + "font_class": "refreshempty", + "unicode": "\ue6bf" + }, + { + "font_class": "reload", + "unicode": "\ue6b2" + }, + { + "font_class": "right", + "unicode": "\ue6b5" + }, + { + "font_class": "scan", + "unicode": "\ue62a" + }, + { + "font_class": "search", + "unicode": "\ue654" + }, + { + "font_class": "settings", + "unicode": "\ue653" + }, + { + "font_class": "settings-filled", + "unicode": "\ue6ce" + }, + { + "font_class": "shop", + "unicode": "\ue62f" + }, + { + "font_class": "shop-filled", + "unicode": "\ue6cd" + }, + { + "font_class": "smallcircle", + "unicode": "\ue67c" + }, + { + "font_class": "smallcircle-filled", + "unicode": "\ue665" + }, + { + "font_class": "sound", + "unicode": "\ue684" + }, + { + "font_class": "sound-filled", + "unicode": "\ue686" + }, + { + "font_class": "spinner-cycle", + "unicode": "\ue68a" + }, + { + "font_class": "staff", + "unicode": "\ue6a7" + }, + { + "font_class": "staff-filled", + "unicode": "\ue6cb" + }, + { + "font_class": "star", + "unicode": "\ue688" + }, + { + "font_class": "star-filled", + "unicode": "\ue68f" + }, + { + "font_class": "starhalf", + "unicode": "\ue683" + }, + { + "font_class": "trash", + "unicode": "\ue687" + }, + { + "font_class": "trash-filled", + "unicode": "\ue685" + }, + { + "font_class": "tune", + "unicode": "\ue6aa" + }, + { + "font_class": "tune-filled", + "unicode": "\ue6ca" + }, + { + "font_class": "undo", + "unicode": "\ue64f" + }, + { + "font_class": "undo-filled", + "unicode": "\ue64c" + }, + { + "font_class": "up", + "unicode": "\ue6b6" + }, + { + "font_class": "top", + "unicode": "\ue6b6" + }, + { + "font_class": "upload", + "unicode": "\ue690" + }, + { + "font_class": "upload-filled", + "unicode": "\ue68e" + }, + { + "font_class": "videocam", + "unicode": "\ue68c" + }, + { + "font_class": "videocam-filled", + "unicode": "\ue689" + }, + { + "font_class": "vip", + "unicode": "\ue6a8" + }, + { + "font_class": "vip-filled", + "unicode": "\ue6c6" + }, + { + "font_class": "wallet", + "unicode": "\ue6b1" + }, + { + "font_class": "wallet-filled", + "unicode": "\ue6c2" + }, + { + "font_class": "weibo", + "unicode": "\ue68b" + }, + { + "font_class": "weixin", + "unicode": "\ue691" + } +] + +// export const fontData = JSON.parse(fontDataJson) diff --git a/smart-app/src/uni_modules/uni-icons/package.json b/smart-app/src/uni_modules/uni-icons/package.json new file mode 100644 index 00000000..397be839 --- /dev/null +++ b/smart-app/src/uni_modules/uni-icons/package.json @@ -0,0 +1,88 @@ +{ + "id": "uni-icons", + "displayName": "uni-icons 图标", + "version": "2.0.9", + "description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。", + "keywords": [ + "uni-ui", + "uniui", + "icon", + "图标" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.2.14" + }, + "directories": { + "example": "../../temps/example_temps" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y", + "app-uvue": "y" + }, + "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" + }, + "快应用": { + "华为": "y", + "联盟": "y" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/smart-app/src/uni_modules/uni-icons/readme.md b/smart-app/src/uni_modules/uni-icons/readme.md new file mode 100644 index 00000000..86234ba1 --- /dev/null +++ b/smart-app/src/uni_modules/uni-icons/readme.md @@ -0,0 +1,8 @@ +## Icons 图标 +> **组件名:uni-icons** +> 代码块: `uIcons` + +用于展示 icons 图标 。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-icons) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 diff --git a/smart-app/src/uni_modules/uni-load-more/changelog.md b/smart-app/src/uni_modules/uni-load-more/changelog.md new file mode 100644 index 00000000..8f03f1d5 --- /dev/null +++ b/smart-app/src/uni_modules/uni-load-more/changelog.md @@ -0,0 +1,19 @@ +## 1.3.3(2022-01-20) +- 新增 showText属性 ,是否显示文本 +## 1.3.2(2022-01-19) +- 修复 nvue 平台下不显示文本的bug +## 1.3.1(2022-01-19) +- 修复 微信小程序平台样式选择器报警告的问题 +## 1.3.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-load-more](https://uniapp.dcloud.io/component/uniui/uni-load-more) +## 1.2.1(2021-08-24) +- 新增 支持国际化 +## 1.2.0(2021-07-30) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 1.1.8(2021-05-12) +- 新增 组件示例地址 +## 1.1.7(2021-03-30) +- 修复 uni-load-more 在首页使用时,h5 平台报 'uni is not defined' 的 bug +## 1.1.6(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/smart-app/src/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json b/smart-app/src/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json new file mode 100644 index 00000000..a4f14a54 --- /dev/null +++ b/smart-app/src/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json @@ -0,0 +1,5 @@ +{ + "uni-load-more.contentdown": "Pull up to show more", + "uni-load-more.contentrefresh": "loading...", + "uni-load-more.contentnomore": "No more data" +} diff --git a/smart-app/src/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js b/smart-app/src/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js new file mode 100644 index 00000000..de7509c8 --- /dev/null +++ b/smart-app/src/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js @@ -0,0 +1,8 @@ +import en from './en.json' +import zhHans from './zh-Hans.json' +import zhHant from './zh-Hant.json' +export default { + en, + 'zh-Hans': zhHans, + 'zh-Hant': zhHant +} diff --git a/smart-app/src/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json b/smart-app/src/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json new file mode 100644 index 00000000..f15d5105 --- /dev/null +++ b/smart-app/src/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json @@ -0,0 +1,5 @@ +{ + "uni-load-more.contentdown": "上拉显示更多", + "uni-load-more.contentrefresh": "正在加载...", + "uni-load-more.contentnomore": "没有更多数据了" +} diff --git a/smart-app/src/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json b/smart-app/src/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json new file mode 100644 index 00000000..a255c6de --- /dev/null +++ b/smart-app/src/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json @@ -0,0 +1,5 @@ +{ + "uni-load-more.contentdown": "上拉顯示更多", + "uni-load-more.contentrefresh": "正在加載...", + "uni-load-more.contentnomore": "沒有更多數據了" +} diff --git a/smart-app/src/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue b/smart-app/src/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue new file mode 100644 index 00000000..e5eff4d6 --- /dev/null +++ b/smart-app/src/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue @@ -0,0 +1,399 @@ + + + + + diff --git a/smart-app/src/uni_modules/uni-load-more/package.json b/smart-app/src/uni_modules/uni-load-more/package.json new file mode 100644 index 00000000..2fa6f040 --- /dev/null +++ b/smart-app/src/uni_modules/uni-load-more/package.json @@ -0,0 +1,86 @@ +{ + "id": "uni-load-more", + "displayName": "uni-load-more 加载更多", + "version": "1.3.3", + "description": "LoadMore 组件,常用在列表里面,做滚动加载使用。", + "keywords": [ + "uni-ui", + "uniui", + "加载更多", + "load-more" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y" + }, + "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" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-load-more/readme.md b/smart-app/src/uni_modules/uni-load-more/readme.md new file mode 100644 index 00000000..54dc1fad --- /dev/null +++ b/smart-app/src/uni_modules/uni-load-more/readme.md @@ -0,0 +1,14 @@ + + +### LoadMore 加载更多 +> **组件名:uni-load-more** +> 代码块: `uLoadMore` + + +用于列表中,做滚动加载使用,展示 loading 的各种状态。 + + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-load-more) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 + + diff --git a/smart-app/src/uni_modules/uni-mescroll/changelog.md b/smart-app/src/uni_modules/uni-mescroll/changelog.md new file mode 100644 index 00000000..dd6dd727 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/changelog.md @@ -0,0 +1,8 @@ +## 1.3.8(2023-03-27) +1. 新增useMescroll的hook, 支持vue3 script setup的写法 +2. 新增vue3 script setup的示例 ( 根据vue2的示例,全部重写了一遍 ) +3. mescroll-body 和 mescroll-uni 无需再写 ref="mescrollRef" +4. 解决mescroll-uni在页面渲染之后,无法动态设置height的问题 +5. 解决renderjs在h5返回有时候无法正常滑动的问题 +6. 修复小程序编辑器提示 Cannot read property 'nv_optDown' of undefined 的错误 +-by 小瑾同学 diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-body/mescroll-body.css b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-body/mescroll-body.css new file mode 100644 index 00000000..1107710c --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-body/mescroll-body.css @@ -0,0 +1,19 @@ +.mescroll-body { + position: relative; /* 下拉刷新区域相对自身定位 */ + height: auto; /* 不可固定高度,否则overflow:hidden导致无法滑动; 同时使设置的最小高生效,实现列表不满屏仍可下拉*/ + overflow: hidden; /* 当有元素写在mescroll-body标签前面时,可遮住下拉刷新区域 */ + box-sizing: border-box; /* 避免设置padding出现双滚动条的问题 */ +} + +/* 使sticky生效: 父元素不能overflow:hidden或者overflow:auto属性 */ +.mescroll-body.mescorll-sticky{ + overflow: unset !important +} + +/* 适配 iPhoneX */ +@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) { + .mescroll-safearea { + padding-bottom: constant(safe-area-inset-bottom); + padding-bottom: env(safe-area-inset-bottom); + } +} \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-body/mescroll-body.vue b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-body/mescroll-body.vue new file mode 100644 index 00000000..76d77282 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-body/mescroll-body.vue @@ -0,0 +1,400 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/beibei/components/mescroll-down.css b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/beibei/components/mescroll-down.css new file mode 100644 index 00000000..dcefe2da --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/beibei/components/mescroll-down.css @@ -0,0 +1,47 @@ +/*下拉刷新--标语*/ +.mescroll-downwarp .downwarp-slogan{ + display: block; + width: 420rpx; + height: 168rpx; + margin: auto; +} +/*下拉刷新--向下进度动画*/ +.mescroll-downwarp .downwarp-progress{ + display: inline-block; + width: 40rpx; + height: 40rpx; + border: none; + margin: auto; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + background-image: url(https://www.mescroll.com/img/beibei/mescroll-progress.png); + transition: all 300ms; +} +/*下拉刷新--进度条*/ +.mescroll-downwarp .downwarp-loading{ + display: inline-block; + width: 32rpx; + height: 32rpx; + border-radius: 50%; + border: 2rpx solid #FF8095; + border-bottom-color: transparent; +} +/*下拉刷新--吉祥物*/ +.mescroll-downwarp .downwarp-mascot{ + position: absolute; + right: 16rpx; + bottom: 0; + width: 100rpx; + height: 100rpx; + background-size: contain; + background-repeat: no-repeat; + animation: animMascot .6s steps(1,end) infinite; +} +@keyframes animMascot { + 0% {background-image: url(https://www.mescroll.com/img/beibei/mescroll-bb1.png)} + 25% {background-image: url(https://www.mescroll.com/img/beibei/mescroll-bb2.png)} + 50% {background-image: url(https://www.mescroll.com/img/beibei/mescroll-bb3.png)} + 75% {background-image: url(https://www.mescroll.com/img/beibei/mescroll-bb4.png)} + 100% {background-image: url(https://www.mescroll.com/img/beibei/mescroll-bb1.png)} +} \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/beibei/components/mescroll-down.vue b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/beibei/components/mescroll-down.vue new file mode 100644 index 00000000..ee1d3218 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/beibei/components/mescroll-down.vue @@ -0,0 +1,39 @@ + + + + + + diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/beibei/mescroll-body.vue b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/beibei/mescroll-body.vue new file mode 100644 index 00000000..9f572a9e --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/beibei/mescroll-body.vue @@ -0,0 +1,360 @@ + + + + + + + + + + + + + + + diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/beibei/mescroll-uni-option.js b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/beibei/mescroll-uni-option.js new file mode 100644 index 00000000..fbac7788 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/beibei/mescroll-uni-option.js @@ -0,0 +1,49 @@ +// mescroll-uni和mescroll-body 的全局配置 +const GlobalOption = { + down: { + // 其他down的配置参数也可以写,这里只展示了常用的配置: + offset: uni.upx2px(140), // 在列表顶部,下拉大于140upx,松手即可触发下拉刷新的回调 + native: false // 是否使用系统自带的下拉刷新; 默认false; 仅在mescroll-body生效 (值为true时,还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例) + }, + up: { + // 其他up的配置参数也可以写,这里只展示了常用的配置: + offset: 150, // 距底部多远时,触发upCallback + toTop: { + // 回到顶部按钮,需配置src才显示 + src: "https://www.mescroll.com/img/mescroll-totop.png", // 图片路径 (建议放入static目录, 如 /static/img/mescroll-totop.png ) + offset: 1000, // 列表滚动多少距离才显示回到顶部按钮,默认1000px + right: 20, // 到右边的距离, 默认20 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) + bottom: 120, // 到底部的距离, 默认120 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) + width: 72 // 回到顶部图标的宽度, 默认72 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) + }, + empty: { + use: true, // 是否显示空布局 + icon: "https://www.mescroll.com/img/mescroll-empty.png" // 图标路径 (建议放入static目录, 如 /static/img/mescroll-empty.png ) + } + }, + // 国际化配置 + i18n: { + // 中文 + zh: { + up: { + textLoading: '加载中 ...', // 加载中的提示文本 + textNoMore: '-- END --', // 没有更多数据的提示文本 + empty: { + tip: '~ 暂无相关数据 ~' // 空提示 + } + } + }, + // 英文 + en: { + up: { + textLoading: 'loading ...', + textNoMore: '-- END --', + empty: { + tip: '~ absolutely empty ~' + } + } + } + } +} + +export default GlobalOption \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/beibei/mescroll-uni.vue b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/beibei/mescroll-uni.vue new file mode 100644 index 00000000..15a22891 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/beibei/mescroll-uni.vue @@ -0,0 +1,434 @@ + + + + + + + + + + + + + + + diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/components/mescroll-down.css b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/components/mescroll-down.css new file mode 100644 index 00000000..b62ed403 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/components/mescroll-down.css @@ -0,0 +1,44 @@ +/*下拉刷新--上下箭头*/ +.mescroll-downwarp .downwarp-arrow { + display: inline-block; + width: 20px; + height: 20px; + margin: 10px; + background-image: url(https://www.mescroll.com/img/xinlang/mescroll-arrow.png); + background-size: contain; + vertical-align: middle; + transition: all 300ms; +} + +/*下拉刷新--旋转进度条*/ +.mescroll-downwarp .downwarp-progress{ + width: 36px; + height: 36px; + border: none; + margin: auto; + background-size: contain; + animation: progressRotate 0.6s steps(6, start) infinite; +} +@keyframes progressRotate { + 0% { + background-image: url(https://www.mescroll.com/img/xinlang/mescroll-progress1.png); + } + 16% { + background-image: url(https://www.mescroll.com/img/xinlang/mescroll-progress2.png); + } + 32% { + background-image: url(https://www.mescroll.com/img/xinlang/mescroll-progress3.png); + } + 48% { + background-image: url(https://www.mescroll.com/img/xinlang/mescroll-progress4.png); + } + 64% { + background-image: url(https://www.mescroll.com/img/xinlang/mescroll-progress5.png); + } + 80% { + background-image: url(https://www.mescroll.com/img/xinlang/mescroll-progress6.png); + } + 100% { + background-image: url(https://www.mescroll.com/img/xinlang/mescroll-progress1.png); + } +} \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/components/mescroll-down.vue b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/components/mescroll-down.vue new file mode 100644 index 00000000..745d9032 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/components/mescroll-down.vue @@ -0,0 +1,53 @@ + + + + + + diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/components/mescroll-up.css b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/components/mescroll-up.css new file mode 100644 index 00000000..abf51f1d --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/components/mescroll-up.css @@ -0,0 +1,32 @@ +/*上拉加载--旋转进度条*/ +.mescroll-upwarp .upwarp-progress { + width: 36px; + height: 36px; + border: none; + margin: auto; + background-size: contain; + animation: progressRotate 0.6s steps(6, start) infinite; +} +@keyframes progressRotate { + 0% { + background-image: url(https://www.mescroll.com/img/xinlang/mescroll-progress1.png); + } + 16% { + background-image: url(https://www.mescroll.com/img/xinlang/mescroll-progress2.png); + } + 32% { + background-image: url(https://www.mescroll.com/img/xinlang/mescroll-progress3.png); + } + 48% { + background-image: url(https://www.mescroll.com/img/xinlang/mescroll-progress4.png); + } + 64% { + background-image: url(https://www.mescroll.com/img/xinlang/mescroll-progress5.png); + } + 80% { + background-image: url(https://www.mescroll.com/img/xinlang/mescroll-progress6.png); + } + 100% { + background-image: url(https://www.mescroll.com/img/xinlang/mescroll-progress1.png); + } +} \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/components/mescroll-up.vue b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/components/mescroll-up.vue new file mode 100644 index 00000000..31bd42a1 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/components/mescroll-up.vue @@ -0,0 +1,40 @@ + + + + + + diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/mescroll-body.vue b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/mescroll-body.vue new file mode 100644 index 00000000..cb2376a3 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/mescroll-body.vue @@ -0,0 +1,380 @@ + + + + + + + + + + + + + + + diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/mescroll-uni-option.js b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/mescroll-uni-option.js new file mode 100644 index 00000000..55d331ec --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/mescroll-uni-option.js @@ -0,0 +1,64 @@ +// 全局配置 +// mescroll-body 和 mescroll-uni 通用 +const GlobalOption = { + down: { + // 其他down的配置参数也可以写,这里只展示了常用的配置: + offset: 80, // 在列表顶部,下拉大于80px,松手即可触发下拉刷新的回调 + native: false // 是否使用系统自带的下拉刷新; 默认false; 仅在mescroll-body生效 (值为true时,还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例) + }, + up: { + // 其他up的配置参数也可以写,这里只展示了常用的配置: + offset: 150, // 距底部多远时,触发upCallback,仅mescroll-uni生效 ( mescroll-body配置的是pages.json的 onReachBottomDistance ) + toTop: { + // 回到顶部按钮,需配置src才显示 + src: "https://www.mescroll.com/img/mescroll-totop.png", // 图片路径 (建议放入static目录, 如 /static/img/mescroll-totop.png ) + offset: 1000, // 列表滚动多少距离才显示回到顶部按钮,默认1000px + right: 20, // 到右边的距离, 默认20 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) + bottom: 120, // 到底部的距离, 默认120 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) + width: 72 // 回到顶部图标的宽度, 默认72 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) + }, + empty: { + use: true, // 是否显示空布局 + icon: "https://www.mescroll.com/img/mescroll-empty.png" // 图标路径 (建议放入static目录, 如 /static/img/mescroll-empty.png ) + } + }, + // 国际化配置 + i18n: { + // 中文 + zh: { + down: { + textInOffset: '下拉刷新', // 下拉的距离在offset范围内的提示文本 + textOutOffset: '释放更新', // 下拉的距离大于offset范围的提示文本 + textLoading: '加载中 ...', // 加载中的提示文本 + textSuccess: '加载成功', // 加载成功的文本 + textErr: '加载失败', // 加载失败的文本 + }, + up: { + textLoading: '加载中 ...', // 加载中的提示文本 + textNoMore: '-- END --', // 没有更多数据的提示文本 + empty: { + tip: '~ 空空如也 ~' // 空提示 + } + } + }, + // 英文 + en: { + down: { + textInOffset: 'drop down refresh', + textOutOffset: 'release updates', + textLoading: 'loading ...', + textSuccess: 'loaded successfully', + textErr: 'loading failed' + }, + up: { + textLoading: 'loading ...', + textNoMore: '-- END --', + empty: { + tip: '~ absolutely empty ~' + } + } + } + } +} + +export default GlobalOption diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/mescroll-uni.vue b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/mescroll-uni.vue new file mode 100644 index 00000000..8c8b6de4 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-diy/xinlang/mescroll-uni.vue @@ -0,0 +1,459 @@ + + + + + + + + + + + + + + + diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-empty/mescroll-empty.vue b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-empty/mescroll-empty.vue new file mode 100644 index 00000000..32b40696 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-empty/mescroll-empty.vue @@ -0,0 +1,116 @@ + + + + + + diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/components/mescroll-down.css b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/components/mescroll-down.css new file mode 100644 index 00000000..72bf106c --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/components/mescroll-down.css @@ -0,0 +1,55 @@ +/* 下拉刷新区域 */ +.mescroll-downwarp { + position: absolute; + top: -100%; + left: 0; + width: 100%; + height: 100%; + text-align: center; +} + +/* 下拉刷新--内容区,定位于区域底部 */ +.mescroll-downwarp .downwarp-content { + position: absolute; + left: 0; + bottom: 0; + width: 100%; + min-height: 60rpx; + padding: 20rpx 0; + text-align: center; +} + +/* 下拉刷新--提示文本 */ +.mescroll-downwarp .downwarp-tip { + display: inline-block; + font-size: 28rpx; + vertical-align: middle; + margin-left: 16rpx; + /* color: gray; 已在style设置color,此处删去*/ +} + +/* 下拉刷新--旋转进度条 */ +.mescroll-downwarp .downwarp-progress { + display: inline-block; + width: 32rpx; + height: 32rpx; + border-radius: 50%; + border: 2rpx solid gray; + border-bottom-color: transparent !important; /*已在style设置border-color,此处需加 !important*/ + vertical-align: middle; +} + +/* 旋转动画 */ +.mescroll-downwarp .mescroll-rotate { + animation: mescrollDownRotate 0.6s linear infinite; +} + +@keyframes mescrollDownRotate { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/components/mescroll-down.vue b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/components/mescroll-down.vue new file mode 100644 index 00000000..9fd1567f --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/components/mescroll-down.vue @@ -0,0 +1,47 @@ + + + + + + diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/components/mescroll-top.vue b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/components/mescroll-top.vue new file mode 100644 index 00000000..a7c7e3a6 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/components/mescroll-top.vue @@ -0,0 +1,99 @@ + + + + + + diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/components/mescroll-up.css b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/components/mescroll-up.css new file mode 100644 index 00000000..cbf48cd2 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/components/mescroll-up.css @@ -0,0 +1,47 @@ +/* 上拉加载区域 */ +.mescroll-upwarp { + box-sizing: border-box; + min-height: 110rpx; + padding: 30rpx 0; + text-align: center; + clear: both; +} + +/*提示文本 */ +.mescroll-upwarp .upwarp-tip, +.mescroll-upwarp .upwarp-nodata { + display: inline-block; + font-size: 28rpx; + vertical-align: middle; + /* color: gray; 已在style设置color,此处删去*/ +} + +.mescroll-upwarp .upwarp-tip { + margin-left: 16rpx; +} + +/*旋转进度条 */ +.mescroll-upwarp .upwarp-progress { + display: inline-block; + width: 32rpx; + height: 32rpx; + border-radius: 50%; + border: 2rpx solid gray; + border-bottom-color: transparent !important; /*已在style设置border-color,此处需加 !important*/ + vertical-align: middle; +} + +/* 旋转动画 */ +.mescroll-upwarp .mescroll-rotate { + animation: mescrollUpRotate 0.6s linear infinite; +} + +@keyframes mescrollUpRotate { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/components/mescroll-up.vue b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/components/mescroll-up.vue new file mode 100644 index 00000000..11c2e1fb --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/components/mescroll-up.vue @@ -0,0 +1,39 @@ + + + + + + diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-i18n.js b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-i18n.js new file mode 100644 index 00000000..2b6a50f0 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-i18n.js @@ -0,0 +1,15 @@ +// 国际化工具类 +const mescrollI18n = { + // 默认语言 + def: "zh", + // 获取当前语言类型 + getType(){ + return uni.getStorageSync("mescroll-i18n") || this.def + }, + // 设置当前语言类型 + setType(type){ + uni.setStorageSync("mescroll-i18n", type) + } +} + +export default mescrollI18n diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-mixins.js b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-mixins.js new file mode 100644 index 00000000..10f68c09 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-mixins.js @@ -0,0 +1,46 @@ +// mescroll-body 和 mescroll-uni 通用 +const MescrollMixin = { + data() { + return { + mescroll: null //mescroll实例对象 + } + }, + // 注册系统自带的下拉刷新 (配置down.native为true时生效, 还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例) + onPullDownRefresh(){ + this.mescroll && this.mescroll.onPullDownRefresh(); + }, + // 注册列表滚动事件,用于判定在顶部可下拉刷新,在指定位置可显示隐藏回到顶部按钮 (此方法为页面生命周期,无法在子组件中触发, 仅在mescroll-body生效) + onPageScroll(e) { + this.mescroll && this.mescroll.onPageScroll(e); + }, + // 注册滚动到底部的事件,用于上拉加载 (此方法为页面生命周期,无法在子组件中触发, 仅在mescroll-body生效) + onReachBottom() { + this.mescroll && this.mescroll.onReachBottom(); + }, + methods: { + // mescroll组件初始化的回调,可获取到mescroll对象 + mescrollInit(mescroll) { + this.mescroll = mescroll; + }, + // 下拉刷新的回调 (mixin默认resetUpScroll) + downCallback() { + if(this.mescroll.optUp.use){ + this.mescroll.resetUpScroll() + }else{ + setTimeout(()=>{ + this.mescroll.endSuccess(); + }, 500) + } + }, + // 上拉加载的回调 + upCallback() { + // mixin默认延时500自动结束加载 + setTimeout(()=>{ + this.mescroll.endErr(); + }, 500) + } + } + +} + +export default MescrollMixin; diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-uni-option.js b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-uni-option.js new file mode 100644 index 00000000..c9229b9d --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-uni-option.js @@ -0,0 +1,64 @@ +// 全局配置 +// mescroll-body 和 mescroll-uni 通用 +const GlobalOption = { + down: { + // 其他down的配置参数也可以写,这里只展示了常用的配置: + offset: 80, // 在列表顶部,下拉大于80px,松手即可触发下拉刷新的回调 + native: false, // 是否使用系统自带的下拉刷新; 默认false; 仅在mescroll-body生效 (值为true时,还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例) + }, + up: { + // 其他up的配置参数也可以写,这里只展示了常用的配置: + offset: 150, // 距底部多远时,触发upCallback,仅mescroll-uni生效 ( mescroll-body配置的是pages.json的 onReachBottomDistance ) + toTop: { + // 回到顶部按钮,需配置src才显示 + src: '/static/images/uni-modules/uni-mescroll/mescroll-totop.png', // 图片路径 (建议放入static目录, 如 /static/img/mescroll-totop.png ) + offset: 1000, // 列表滚动多少距离才显示回到顶部按钮,默认1000px + right: 20, // 到右边的距离, 默认20 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) + bottom: 120, // 到底部的距离, 默认120 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) + width: 72, // 回到顶部图标的宽度, 默认72 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) + }, + empty: { + use: true, // 是否显示空布局 + icon: '/static/images/uni-modules/uni-mescroll/mescroll-empty.png', // 图标路径 (建议放入static目录, 如 /static/img/mescroll-empty.png ) + }, + }, + // 国际化配置 + i18n: { + // 中文 + zh: { + down: { + textInOffset: '下拉刷新', // 下拉的距离在offset范围内的提示文本 + textOutOffset: '释放更新', // 下拉的距离大于offset范围的提示文本 + textLoading: '加载中 ...', // 加载中的提示文本 + textSuccess: '加载成功', // 加载成功的文本 + textErr: '加载失败', // 加载失败的文本 + }, + up: { + textLoading: '加载中 ...', // 加载中的提示文本 + textNoMore: '-- 没有更多了 --', // 没有更多数据的提示文本 + empty: { + tip: '~ 没有任何数据 ~', // 空提示 + }, + }, + }, + // 英文 + en: { + down: { + textInOffset: 'drop down refresh', + textOutOffset: 'release updates', + textLoading: 'loading ...', + textSuccess: 'loaded successfully', + textErr: 'loading failed', + }, + up: { + textLoading: 'loading ...', + textNoMore: '-- END --', + empty: { + tip: '~ absolutely empty ~', + }, + }, + }, + }, +}; + +export default GlobalOption; diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-uni.css b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-uni.css new file mode 100644 index 00000000..39438cdf --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-uni.css @@ -0,0 +1,36 @@ +.mescroll-uni-warp{ + height: 100%; +} + +.mescroll-uni-content{ + height: 100%; +} + +.mescroll-uni { + position: relative; + width: 100%; + height: 100%; + min-height: 200rpx; + overflow-y: auto; + box-sizing: border-box; /* 避免设置padding出现双滚动条的问题 */ +} + +/* 定位的方式固定高度 */ +.mescroll-uni-fixed{ + z-index: 1; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: auto; /* 使right生效 */ + height: auto; /* 使bottom生效 */ +} + +/* 适配 iPhoneX */ +@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) { + .mescroll-safearea { + padding-bottom: constant(safe-area-inset-bottom); + padding-bottom: env(safe-area-inset-bottom); + } +} diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-uni.js b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-uni.js new file mode 100644 index 00000000..3bfdac17 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-uni.js @@ -0,0 +1,799 @@ +/* mescroll + * version 1.3.7 + * 2021-04-12 wenju + * https://www.mescroll.com + */ + +export default function MeScroll(options, isScrollBody) { + let me = this; + me.version = '1.3.7'; // mescroll版本号 + me.options = options || {}; // 配置 + me.isScrollBody = isScrollBody || false; // 滚动区域是否为原生页面滚动; 默认为scroll-view + + me.isDownScrolling = false; // 是否在执行下拉刷新的回调 + me.isUpScrolling = false; // 是否在执行上拉加载的回调 + let hasDownCallback = me.options.down && me.options.down.callback; // 是否配置了down的callback + + // 初始化下拉刷新 + me.initDownScroll(); + // 初始化上拉加载,则初始化 + me.initUpScroll(); + + // 自动加载 + setTimeout(function() { // 待主线程执行完毕再执行,避免new MeScroll未初始化,在回调获取不到mescroll的实例 + // 自动触发下拉刷新 (只有配置了down的callback才自动触发下拉刷新) + if ((me.optDown.use || me.optDown.native) && me.optDown.auto && hasDownCallback) { + if (me.optDown.autoShowLoading) { + me.triggerDownScroll(); // 显示下拉进度,执行下拉回调 + } else { + me.optDown.callback && me.optDown.callback(me); // 不显示下拉进度,直接执行下拉回调 + } + } + // 自动触发上拉加载 + if(!me.isUpAutoLoad){ // 部分小程序(头条小程序)emit是异步, 会导致isUpAutoLoad判断有误, 先延时确保先执行down的callback,再执行up的callback + setTimeout(function(){ + me.optUp.use && me.optUp.auto && !me.isUpAutoLoad && me.triggerUpScroll(); + },100) + } + }, 30); // 需让me.optDown.inited和me.optUp.inited先执行 +} + +/* 配置参数:下拉刷新 */ +MeScroll.prototype.extendDownScroll = function(optDown) { + // 下拉刷新的配置 + MeScroll.extend(optDown, { + use: true, // 是否启用下拉刷新; 默认true + auto: true, // 是否在初始化完毕之后自动执行下拉刷新的回调; 默认true + native: false, // 是否使用系统自带的下拉刷新; 默认false; 仅mescroll-body生效 (值为true时,还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例) + autoShowLoading: false, // 如果设置auto=true(在初始化完毕之后自动执行下拉刷新的回调),那么是否显示下拉刷新的进度; 默认false + isLock: false, // 是否锁定下拉刷新,默认false; + offset: 80, // 在列表顶部,下拉大于80px,松手即可触发下拉刷新的回调 + startTop: 100, // scroll-view快速滚动到顶部时,此时的scroll-top可能大于0, 此值用于控制最大的误差 + inOffsetRate: 1, // 在列表顶部,下拉的距离小于offset时,改变下拉区域高度比例;值小于1且越接近0,高度变化越小,表现为越往下越难拉 + outOffsetRate: 0.2, // 在列表顶部,下拉的距离大于offset时,改变下拉区域高度比例;值小于1且越接近0,高度变化越小,表现为越往下越难拉 + bottomOffset: 20, // 当手指touchmove位置在距离body底部20px范围内的时候结束上拉刷新,避免Webview嵌套导致touchend事件不执行 + minAngle: 45, // 向下滑动最少偏移的角度,取值区间 [0,90];默认45度,即向下滑动的角度大于45度则触发下拉;而小于45度,将不触发下拉,避免与左右滑动的轮播等组件冲突; + textInOffset: '下拉刷新', // 下拉的距离在offset范围内的提示文本 + textOutOffset: '释放更新', // 下拉的距离大于offset范围的提示文本 + textLoading: '加载中 ...', // 加载中的提示文本 + textSuccess: '加载成功', // 加载成功的文本 + textErr: '加载失败', // 加载失败的文本 + beforeEndDelay: 0, // 延时结束的时长 (显示加载成功/失败的时长, android小程序设置此项结束下拉会卡顿, 配置后请注意测试) + bgColor: "transparent", // 背景颜色 (建议在pages.json中再设置一下backgroundColorTop) + textColor: "gray", // 文本颜色 (当bgColor配置了颜色,而textColor未配置时,则textColor会默认为白色) + inited: null, // 下拉刷新初始化完毕的回调 + inOffset: null, // 下拉的距离进入offset范围内那一刻的回调 + outOffset: null, // 下拉的距离大于offset那一刻的回调 + onMoving: null, // 下拉过程中的回调,滑动过程一直在执行; rate下拉区域当前高度与指定距离的比值(inOffset: rate<1; outOffset: rate>=1); downHight当前下拉区域的高度 + beforeLoading: null, // 准备触发下拉刷新的回调: 如果return true,将不触发showLoading和callback回调; 常用来完全自定义下拉刷新, 参考案例【淘宝 v6.8.0】 + showLoading: null, // 显示下拉刷新进度的回调 + afterLoading: null, // 显示下拉刷新进度的回调之后,马上要执行的代码 (如: 在wxs中使用) + beforeEndDownScroll: null, // 准备结束下拉的回调. 返回结束下拉的延时执行时间,默认0ms; 常用于结束下拉之前再显示另外一小段动画,才去隐藏下拉刷新的场景, 参考案例【dotJump】 + endDownScroll: null, // 结束下拉刷新的回调 + afterEndDownScroll: null, // 结束下拉刷新的回调,马上要执行的代码 (如: 在wxs中使用) + callback: function(mescroll) { + // 下拉刷新的回调;默认重置上拉加载列表为第一页 + mescroll.resetUpScroll(); + } + }) +} + +/* 配置参数:上拉加载 */ +MeScroll.prototype.extendUpScroll = function(optUp) { + // 上拉加载的配置 + MeScroll.extend(optUp, { + use: true, // 是否启用上拉加载; 默认true + auto: true, // 是否在初始化完毕之后自动执行上拉加载的回调; 默认true + isLock: false, // 是否锁定上拉加载,默认false; + isBoth: true, // 上拉加载时,如果滑动到列表顶部是否可以同时触发下拉刷新;默认true,两者可同时触发; + callback: null, // 上拉加载的回调;function(page,mescroll){ } + page: { + num: 0, // 当前页码,默认0,回调之前会加1,即callback(page)会从1开始 + size: 10, // 每页数据的数量 + time: null // 加载第一页数据服务器返回的时间; 防止用户翻页时,后台新增了数据从而导致下一页数据重复; + }, + noMoreSize: 5, // 如果列表已无数据,可设置列表的总数量要大于等于5条才显示无更多数据;避免列表数据过少(比如只有一条数据),显示无更多数据会不好看 + offset: 150, // 距底部多远时,触发upCallback,仅mescroll-uni生效 ( mescroll-body配置的是pages.json的 onReachBottomDistance ) + textLoading: '加载中 ...', // 加载中的提示文本 + textNoMore: '-- END --', // 没有更多数据的提示文本 + bgColor: "transparent", // 背景颜色 (建议在pages.json中再设置一下backgroundColorBottom) + textColor: "gray", // 文本颜色 (当bgColor配置了颜色,而textColor未配置时,则textColor会默认为白色) + inited: null, // 初始化完毕的回调 + showLoading: null, // 显示加载中的回调 + showNoMore: null, // 显示无更多数据的回调 + hideUpScroll: null, // 隐藏上拉加载的回调 + errDistance: 60, // endErr的时候需往上滑动一段距离,使其往下滑动时再次触发onReachBottom,仅mescroll-body生效 + toTop: { + // 回到顶部按钮,需配置src才显示 + src: null, // 图片路径,默认null (绝对路径或网络图) + offset: 1000, // 列表滚动多少距离才显示回到顶部按钮,默认1000 + duration: 300, // 回到顶部的动画时长,默认300ms (当值为0或300则使用系统自带回到顶部,更流畅; 其他值则通过step模拟,部分机型可能不够流畅,所以非特殊情况不建议修改此项) + btnClick: null, // 点击按钮的回调 + onShow: null, // 是否显示的回调 + zIndex: 9990, // fixed定位z-index值 + left: null, // 到左边的距离, 默认null. 此项有值时,right不生效. (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx) + right: 20, // 到右边的距离, 默认20 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx) + bottom: 120, // 到底部的距离, 默认120 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx) + safearea: false, // bottom的偏移量是否加上底部安全区的距离, 默认false, 需要适配iPhoneX时使用 (具体的界面如果不配置此项,则取本vue的safearea值) + width: 72, // 回到顶部图标的宽度, 默认72 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx) + radius: "50%" // 圆角, 默认"50%" (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx) + }, + empty: { + use: true, // 是否显示空布局 + icon: null, // 图标路径 + tip: '~ 暂无相关数据 ~', // 提示 + btnText: '', // 按钮 + btnClick: null, // 点击按钮的回调 + onShow: null, // 是否显示的回调 + fixed: false, // 是否使用fixed定位,默认false; 配置fixed为true,以下的top和zIndex才生效 (transform会使fixed失效,最终会降级为absolute) + top: "100rpx", // fixed定位的top值 (完整的单位值,如 "10%"; "100rpx") + zIndex: 99 // fixed定位z-index值 + }, + onScroll: false // 是否监听滚动事件 + }) +} + +/* 配置参数 */ +MeScroll.extend = function(userOption, defaultOption) { + if (!userOption) return defaultOption; + for (let key in defaultOption) { + if (userOption[key] == null) { + let def = defaultOption[key]; + if (def != null && typeof def === 'object') { + userOption[key] = MeScroll.extend({}, def); // 深度匹配 + } else { + userOption[key] = def; + } + } else if (typeof userOption[key] === 'object') { + MeScroll.extend(userOption[key], defaultOption[key]); // 深度匹配 + } + } + return userOption; +} + +/* 简单判断是否配置了颜色 (非透明,非白色) */ +MeScroll.prototype.hasColor = function(color) { + if(!color) return false; + let c = color.toLowerCase(); + return c != "#fff" && c != "#ffffff" && c != "transparent" && c != "white" +} + +/* -------初始化下拉刷新------- */ +MeScroll.prototype.initDownScroll = function() { + let me = this; + // 配置参数 + me.optDown = me.options.down || {}; + if(!me.optDown.textColor && me.hasColor(me.optDown.bgColor)) me.optDown.textColor = "#fff"; // 当bgColor有值且textColor未设置,则textColor默认白色 + me.extendDownScroll(me.optDown); + + // 如果是mescroll-body且配置了native,则禁止自定义的下拉刷新 + if(me.isScrollBody && me.optDown.native){ + me.optDown.use = false + }else{ + me.optDown.native = false // 仅mescroll-body支持,mescroll-uni不支持 + } + + me.downHight = 0; // 下拉区域的高度 + + // 在页面中加入下拉布局 + if (me.optDown.use && me.optDown.inited) { + // 初始化完毕的回调 + setTimeout(function() { // 待主线程执行完毕再执行,避免new MeScroll未初始化,在回调获取不到mescroll的实例 + me.optDown.inited(me); + }, 0) + } +} + +/* 列表touchstart事件 */ +MeScroll.prototype.touchstartEvent = function(e) { + if (!this.optDown.use) return; + + this.startPoint = this.getPoint(e); // 记录起点 + this.startTop = this.getScrollTop(); // 记录此时的滚动条位置 + this.startAngle = 0; // 初始角度 + this.lastPoint = this.startPoint; // 重置上次move的点 + this.maxTouchmoveY = this.getBodyHeight() - this.optDown.bottomOffset; // 手指触摸的最大范围(写在touchstart避免body获取高度为0的情况) + this.inTouchend = false; // 标记不是touchend +} + +/* 列表touchmove事件 */ +MeScroll.prototype.touchmoveEvent = function(e) { + if (!this.optDown.use) return; + let me = this; + + let scrollTop = me.getScrollTop(); // 当前滚动条的距离 + let curPoint = me.getPoint(e); // 当前点 + + let moveY = curPoint.y - me.startPoint.y; // 和起点比,移动的距离,大于0向下拉,小于0向上拉 + + // 向下拉 && 在顶部 + // mescroll-body,直接判定在顶部即可 + // scroll-view在滚动时不会触发touchmove,当触顶/底/左/右时,才会触发touchmove + // scroll-view滚动到顶部时,scrollTop不一定为0,也有可能大于0; 在iOS的APP中scrollTop可能为负数,不一定和startTop相等 + if (moveY > 0 && ( + (me.isScrollBody && scrollTop <= 0) + || + (!me.isScrollBody && (scrollTop <= 0 || (scrollTop <= me.optDown.startTop && scrollTop === me.startTop)) ) + )) { + // 可下拉的条件 + if (!me.inTouchend && !me.isDownScrolling && !me.optDown.isLock && (!me.isUpScrolling || (me.isUpScrolling && + me.optUp.isBoth))) { + + // 下拉的初始角度是否在配置的范围内 + if(!me.startAngle) me.startAngle = me.getAngle(me.lastPoint, curPoint); // 两点之间的角度,区间 [0,90] + if (me.startAngle < me.optDown.minAngle) return; // 如果小于配置的角度,则不往下执行下拉刷新 + + // 如果手指的位置超过配置的距离,则提前结束下拉,避免Webview嵌套导致touchend无法触发 + if (me.maxTouchmoveY > 0 && curPoint.y >= me.maxTouchmoveY) { + me.inTouchend = true; // 标记执行touchend + me.touchendEvent(); // 提前触发touchend + return; + } + + me.preventDefault(e); // 阻止默认事件 + + let diff = curPoint.y - me.lastPoint.y; // 和上次比,移动的距离 (大于0向下,小于0向上) + + // 下拉距离 < 指定距离 + if (me.downHight < me.optDown.offset) { + if (me.movetype !== 1) { + me.movetype = 1; // 加入标记,保证只执行一次 + me.isDownEndSuccess = null; // 重置是否加载成功的状态 (wxs执行的是wxs.wxs) + me.optDown.inOffset && me.optDown.inOffset(me); // 进入指定距离范围内那一刻的回调,只执行一次 + me.isMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来 + } + me.downHight += diff * me.optDown.inOffsetRate; // 越往下,高度变化越小 + + // 指定距离 <= 下拉距离 + } else { + if (me.movetype !== 2) { + me.movetype = 2; // 加入标记,保证只执行一次 + me.optDown.outOffset && me.optDown.outOffset(me); // 下拉超过指定距离那一刻的回调,只执行一次 + me.isMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来 + } + if (diff > 0) { // 向下拉 + me.downHight += diff * me.optDown.outOffsetRate; // 越往下,高度变化越小 + } else { // 向上收 + me.downHight += diff; // 向上收回高度,则向上滑多少收多少高度 + } + } + + me.downHight = Math.round(me.downHight) // 取整 + let rate = me.downHight / me.optDown.offset; // 下拉区域当前高度与指定距离的比值 + me.optDown.onMoving && me.optDown.onMoving(me, rate, me.downHight); // 下拉过程中的回调,一直在执行 + } + } + + me.lastPoint = curPoint; // 记录本次移动的点 +} + +/* 列表touchend事件 */ +MeScroll.prototype.touchendEvent = function(e) { + if (!this.optDown.use) return; + // 如果下拉区域高度已改变,则需重置回来 + if (this.isMoveDown) { + if (this.downHight >= this.optDown.offset) { + // 符合触发刷新的条件 + this.triggerDownScroll(); + } else { + // 不符合的话 则重置 + this.downHight = 0; + this.endDownScrollCall(this); + } + this.movetype = 0; + this.isMoveDown = false; + } else if (!this.isScrollBody && this.getScrollTop() === this.startTop) { // scroll-view到顶/左/右/底的滑动事件 + let isScrollUp = this.getPoint(e).y - this.startPoint.y < 0; // 和起点比,移动的距离,大于0向下拉,小于0向上拉 + // 上滑 + if (isScrollUp) { + // 需检查滑动的角度 + let angle = this.getAngle(this.getPoint(e), this.startPoint); // 两点之间的角度,区间 [0,90] + if (angle > 80) { + // 检查并触发上拉 + this.triggerUpScroll(true); + } + } + } +} + +/* 根据点击滑动事件获取第一个手指的坐标 */ +MeScroll.prototype.getPoint = function(e) { + if (!e) { + return { + x: 0, + y: 0 + } + } + if (e.touches && e.touches[0]) { + return { + x: e.touches[0].pageX, + y: e.touches[0].pageY + } + } else if (e.changedTouches && e.changedTouches[0]) { + return { + x: e.changedTouches[0].pageX, + y: e.changedTouches[0].pageY + } + } else { + return { + x: e.clientX, + y: e.clientY + } + } +} + +/* 计算两点之间的角度: 区间 [0,90]*/ +MeScroll.prototype.getAngle = function(p1, p2) { + let x = Math.abs(p1.x - p2.x); + let y = Math.abs(p1.y - p2.y); + let z = Math.sqrt(x * x + y * y); + let angle = 0; + if (z !== 0) { + angle = Math.asin(y / z) / Math.PI * 180; + } + return angle +} + +/* 触发下拉刷新 */ +MeScroll.prototype.triggerDownScroll = function() { + if (this.optDown.beforeLoading && this.optDown.beforeLoading(this)) { + //return true则处于完全自定义状态 + } else { + this.showDownScroll(); // 下拉刷新中... + !this.optDown.native && this.optDown.callback && this.optDown.callback(this); // 执行回调,联网加载数据 + } +} + +/* 显示下拉进度布局 */ +MeScroll.prototype.showDownScroll = function() { + this.isDownScrolling = true; // 标记下拉中 + if (this.optDown.native) { + uni.startPullDownRefresh(); // 系统自带的下拉刷新 + this.showDownLoadingCall(0); // 仍触发showLoading,因为上拉加载用到 + } else{ + this.downHight = this.optDown.offset; // 更新下拉区域高度 + this.showDownLoadingCall(this.downHight); // 下拉刷新中... + } +} + +MeScroll.prototype.showDownLoadingCall = function(downHight) { + this.optDown.showLoading && this.optDown.showLoading(this, downHight); // 下拉刷新中... + this.optDown.afterLoading && this.optDown.afterLoading(this, downHight); // 下拉刷新中...触发之后马上要执行的代码 +} + +/* 显示系统自带的下拉刷新时需要处理的业务 */ +MeScroll.prototype.onPullDownRefresh = function() { + this.isDownScrolling = true; // 标记下拉中 + this.showDownLoadingCall(0); // 仍触发showLoading,因为上拉加载用到 + this.optDown.callback && this.optDown.callback(this); // 执行回调,联网加载数据 +} + +/* 结束下拉刷新 */ +MeScroll.prototype.endDownScroll = function() { + if (this.optDown.native) { // 结束原生下拉刷新 + this.isDownScrolling = false; + this.endDownScrollCall(this); + uni.stopPullDownRefresh(); + return + } + let me = this; + // 结束下拉刷新的方法 + let endScroll = function() { + me.downHight = 0; + me.isDownScrolling = false; + me.endDownScrollCall(me); + if(!me.isScrollBody){ + me.setScrollHeight(0) // scroll-view重置滚动区域,使数据不满屏时仍可检查触发翻页 + me.scrollTo(0,0) // scroll-view需重置滚动条到顶部,避免startTop大于0时,对下拉刷新的影响 + } + } + // 结束下拉刷新时的回调 + let delay = 0; + if (me.optDown.beforeEndDownScroll) { + delay = me.optDown.beforeEndDownScroll(me); // 结束下拉刷新的延时,单位ms + if(me.isDownEndSuccess == null) delay = 0; // 没有执行加载中,则不延时 + } + if (typeof delay === 'number' && delay > 0) { + setTimeout(endScroll, delay); + } else { + endScroll(); + } +} + +MeScroll.prototype.endDownScrollCall = function() { + this.optDown.endDownScroll && this.optDown.endDownScroll(this); + this.optDown.afterEndDownScroll && this.optDown.afterEndDownScroll(this); +} + +/* 锁定下拉刷新:isLock=ture,null锁定;isLock=false解锁 */ +MeScroll.prototype.lockDownScroll = function(isLock) { + if (isLock == null) isLock = true; + this.optDown.isLock = isLock; +} + +/* 锁定上拉加载:isLock=ture,null锁定;isLock=false解锁 */ +MeScroll.prototype.lockUpScroll = function(isLock) { + if (isLock == null) isLock = true; + this.optUp.isLock = isLock; +} + +/* -------初始化上拉加载------- */ +MeScroll.prototype.initUpScroll = function() { + let me = this; + // 配置参数 + me.optUp = me.options.up || {use: false} + if(!me.optUp.textColor && me.hasColor(me.optUp.bgColor)) me.optUp.textColor = "#fff"; // 当bgColor有值且textColor未设置,则textColor默认白色 + me.extendUpScroll(me.optUp); + + if (me.optUp.use === false) return; // 配置不使用上拉加载时,则不初始化上拉布局 + me.optUp.hasNext = true; // 如果使用上拉,则默认有下一页 + me.startNum = me.optUp.page.num + 1; // 记录page开始的页码 + + // 初始化完毕的回调 + if (me.optUp.inited) { + setTimeout(function() { // 待主线程执行完毕再执行,避免new MeScroll未初始化,在回调获取不到mescroll的实例 + me.optUp.inited(me); + }, 0) + } +} + +/*滚动到底部的事件 (仅mescroll-body生效)*/ +MeScroll.prototype.onReachBottom = function() { + if (this.isScrollBody && !this.isUpScrolling) { // 只能支持下拉刷新的时候同时可以触发上拉加载,否则滚动到底部就需要上滑一点才能触发onReachBottom + if (!this.optUp.isLock && this.optUp.hasNext) { + this.triggerUpScroll(); + } + } +} + +/*列表滚动事件 (仅mescroll-body生效)*/ +MeScroll.prototype.onPageScroll = function(e) { + if (!this.isScrollBody) return; + + // 更新滚动条的位置 (主要用于判断下拉刷新时,滚动条是否在顶部) + this.setScrollTop(e.scrollTop); + + // 顶部按钮的显示隐藏 + if (e.scrollTop >= this.optUp.toTop.offset) { + this.showTopBtn(); + } else { + this.hideTopBtn(); + } +} + +/*列表滚动事件*/ +MeScroll.prototype.scroll = function(e, onScroll) { + // 更新滚动条的位置 + this.setScrollTop(e.scrollTop); + // 更新滚动内容高度 + this.setScrollHeight(e.scrollHeight); + + // 向上滑还是向下滑动 + if (this.preScrollY == null) this.preScrollY = 0; + this.isScrollUp = e.scrollTop - this.preScrollY > 0; + this.preScrollY = e.scrollTop; + + // 上滑 && 检查并触发上拉 + this.isScrollUp && this.triggerUpScroll(true); + + // 顶部按钮的显示隐藏 + if (e.scrollTop >= this.optUp.toTop.offset) { + this.showTopBtn(); + } else { + this.hideTopBtn(); + } + + // 滑动监听 + this.optUp.onScroll && onScroll && onScroll() +} + +/* 触发上拉加载 */ +MeScroll.prototype.triggerUpScroll = function(isCheck) { + if (!this.isUpScrolling && this.optUp.use && this.optUp.callback) { + // 是否校验在底部; 默认不校验 + if (isCheck === true) { + let canUp = false; + // 还有下一页 && 没有锁定 && 不在下拉中 + if (this.optUp.hasNext && !this.optUp.isLock && !this.isDownScrolling) { + if (this.getScrollBottom() <= this.optUp.offset) { // 到底部 + canUp = true; // 标记可上拉 + } + } + if (canUp === false) return; + } + this.showUpScroll(); // 上拉加载中... + this.optUp.page.num++; // 预先加一页,如果失败则减回 + this.isUpAutoLoad = true; // 标记上拉已经自动执行过,避免初始化时多次触发上拉回调 + this.num = this.optUp.page.num; // 把最新的页数赋值在mescroll上,避免对page的影响 + this.size = this.optUp.page.size; // 把最新的页码赋值在mescroll上,避免对page的影响 + this.time = this.optUp.page.time; // 把最新的页码赋值在mescroll上,避免对page的影响 + this.optUp.callback(this); // 执行回调,联网加载数据 + } +} + +/* 显示上拉加载中 */ +MeScroll.prototype.showUpScroll = function() { + this.isUpScrolling = true; // 标记上拉加载中 + this.optUp.showLoading && this.optUp.showLoading(this); // 回调 +} + +/* 显示上拉无更多数据 */ +MeScroll.prototype.showNoMore = function() { + this.optUp.hasNext = false; // 标记无更多数据 + this.optUp.showNoMore && this.optUp.showNoMore(this); // 回调 +} + +/* 隐藏上拉区域**/ +MeScroll.prototype.hideUpScroll = function() { + this.optUp.hideUpScroll && this.optUp.hideUpScroll(this); // 回调 +} + +/* 结束上拉加载 */ +MeScroll.prototype.endUpScroll = function(isShowNoMore) { + if (isShowNoMore != null) { // isShowNoMore=null,不处理下拉状态,下拉刷新的时候调用 + if (isShowNoMore) { + this.showNoMore(); // isShowNoMore=true,显示无更多数据 + } else { + this.hideUpScroll(); // isShowNoMore=false,隐藏上拉加载 + } + } + this.isUpScrolling = false; // 标记结束上拉加载 +} + +/* 重置上拉加载列表为第一页 + *isShowLoading 是否显示进度布局; + * 1.默认null,不传参,则显示上拉加载的进度布局 + * 2.传参true, 则显示下拉刷新的进度布局 + * 3.传参false,则不显示上拉和下拉的进度 (常用于静默更新列表数据) + */ +MeScroll.prototype.resetUpScroll = function(isShowLoading) { + if (this.optUp && this.optUp.use) { + let page = this.optUp.page; + this.prePageNum = page.num; // 缓存重置前的页码,加载失败可退回 + this.prePageTime = page.time; // 缓存重置前的时间,加载失败可退回 + page.num = this.startNum; // 重置为第一页 + page.time = null; // 重置时间为空 + if (!this.isDownScrolling && isShowLoading !== false) { // 如果不是下拉刷新触发的resetUpScroll并且不配置列表静默更新,则显示进度; + if (isShowLoading == null) { + this.removeEmpty(); // 移除空布局 + this.showUpScroll(); // 不传参,默认显示上拉加载的进度布局 + } else { + this.showDownScroll(); // 传true,显示下拉刷新的进度布局,不清空列表 + } + } + this.isUpAutoLoad = true; // 标记上拉已经自动执行过,避免初始化时多次触发上拉回调 + this.num = page.num; // 把最新的页数赋值在mescroll上,避免对page的影响 + this.size = page.size; // 把最新的页码赋值在mescroll上,避免对page的影响 + this.time = page.time; // 把最新的页码赋值在mescroll上,避免对page的影响 + this.optUp.callback && this.optUp.callback(this); // 执行上拉回调 + } +} + +/* 设置page.num的值 */ +MeScroll.prototype.setPageNum = function(num) { + this.optUp.page.num = num - 1; +} + +/* 设置page.size的值 */ +MeScroll.prototype.setPageSize = function(size) { + this.optUp.page.size = size; +} + +/* 联网回调成功,结束下拉刷新和上拉加载 + * dataSize: 当前页的数据量(必传) + * totalPage: 总页数(必传) + * systime: 服务器时间 (可空) + */ +MeScroll.prototype.endByPage = function(dataSize, totalPage, systime) { + let hasNext; + if (this.optUp.use && totalPage != null) hasNext = this.optUp.page.num < totalPage; // 是否还有下一页 + this.endSuccess(dataSize, hasNext, systime); +} + +/* 联网回调成功,结束下拉刷新和上拉加载 + * dataSize: 当前页的数据量(必传) + * totalSize: 列表所有数据总数量(必传) + * systime: 服务器时间 (可空) + */ +MeScroll.prototype.endBySize = function(dataSize, totalSize, systime) { + let hasNext; + if (this.optUp.use && totalSize != null) { + let loadSize = (this.optUp.page.num - 1) * this.optUp.page.size + dataSize; // 已加载的数据总数 + hasNext = loadSize < totalSize; // 是否还有下一页 + } + this.endSuccess(dataSize, hasNext, systime); +} + +/* 联网回调成功,结束下拉刷新和上拉加载 + * dataSize: 当前页的数据个数(不是所有页的数据总和),用于上拉加载判断是否还有下一页.如果不传,则会判断还有下一页 + * hasNext: 是否还有下一页,布尔类型;用来解决这个小问题:比如列表共有20条数据,每页加载10条,共2页.如果只根据dataSize判断,则需翻到第三页才会知道无更多数据,如果传了hasNext,则翻到第二页即可显示无更多数据. + * systime: 服务器时间(可空);用来解决这个小问题:当准备翻下一页时,数据库新增了几条记录,此时翻下一页,前面的几条数据会和上一页的重复;这里传入了systime,那么upCallback的page.time就会有值,把page.time传给服务器,让后台过滤新加入的那几条记录 + */ +MeScroll.prototype.endSuccess = function(dataSize, hasNext, systime) { + let me = this; + // 结束下拉刷新 + if (me.isDownScrolling) { + me.isDownEndSuccess = true + me.endDownScroll(); + } + + // 结束上拉加载 + if (me.optUp.use) { + let isShowNoMore; // 是否已无更多数据 + if (dataSize != null) { + let pageNum = me.optUp.page.num; // 当前页码 + let pageSize = me.optUp.page.size; // 每页长度 + // 如果是第一页 + if (pageNum === 1) { + if (systime) me.optUp.page.time = systime; // 设置加载列表数据第一页的时间 + } + if (dataSize < pageSize || hasNext === false) { + // 返回的数据不满一页时,则说明已无更多数据 + me.optUp.hasNext = false; + if (dataSize === 0 && pageNum === 1) { + // 如果第一页无任何数据且配置了空布局 + isShowNoMore = false; + me.showEmpty(); + } else { + // 总列表数少于配置的数量,则不显示无更多数据 + let allDataSize = (pageNum - 1) * pageSize + dataSize; + if (allDataSize < me.optUp.noMoreSize) { + isShowNoMore = false; + } else { + isShowNoMore = true; + } + me.removeEmpty(); // 移除空布局 + } + } else { + // 还有下一页 + isShowNoMore = false; + me.optUp.hasNext = true; + me.removeEmpty(); // 移除空布局 + } + } + + // 隐藏上拉 + me.endUpScroll(isShowNoMore); + } +} + +/* 回调失败,结束下拉刷新和上拉加载 */ +MeScroll.prototype.endErr = function(errDistance) { + // 结束下拉,回调失败重置回原来的页码和时间 + if (this.isDownScrolling) { + this.isDownEndSuccess = false + let page = this.optUp.page; + if (page && this.prePageNum) { + page.num = this.prePageNum; + page.time = this.prePageTime; + } + this.endDownScroll(); + } + // 结束上拉,回调失败重置回原来的页码 + if (this.isUpScrolling) { + this.optUp.page.num--; + this.endUpScroll(false); + // 如果是mescroll-body,则需往回滚一定距离 + if(this.isScrollBody && errDistance !== 0){ // 不处理0 + if(!errDistance) errDistance = this.optUp.errDistance; // 不传,则取默认 + this.scrollTo(this.getScrollTop() - errDistance, 0) // 往上回滚的距离 + } + } +} + +/* 显示空布局 */ +MeScroll.prototype.showEmpty = function() { + this.optUp.empty.use && this.optUp.empty.onShow && this.optUp.empty.onShow(true) +} + +/* 移除空布局 */ +MeScroll.prototype.removeEmpty = function() { + this.optUp.empty.use && this.optUp.empty.onShow && this.optUp.empty.onShow(false) +} + +/* 显示回到顶部的按钮 */ +MeScroll.prototype.showTopBtn = function() { + if (!this.topBtnShow) { + this.topBtnShow = true; + this.optUp.toTop.onShow && this.optUp.toTop.onShow(true); + } +} + +/* 隐藏回到顶部的按钮 */ +MeScroll.prototype.hideTopBtn = function() { + if (this.topBtnShow) { + this.topBtnShow = false; + this.optUp.toTop.onShow && this.optUp.toTop.onShow(false); + } +} + +/* 获取滚动条的位置 */ +MeScroll.prototype.getScrollTop = function() { + return this.scrollTop || 0 +} + +/* 记录滚动条的位置 */ +MeScroll.prototype.setScrollTop = function(y) { + this.scrollTop = y; +} + +/* 滚动到指定位置 */ +MeScroll.prototype.scrollTo = function(y, t) { + this.myScrollTo && this.myScrollTo(y, t) // scrollview需自定义回到顶部方法 +} + +/* 自定义scrollTo */ +MeScroll.prototype.resetScrollTo = function(myScrollTo) { + this.myScrollTo = myScrollTo +} + +/* 滚动条到底部的距离 */ +MeScroll.prototype.getScrollBottom = function() { + return this.getScrollHeight() - this.getClientHeight() - this.getScrollTop() +} + +/* 计步器 + star: 开始值 + end: 结束值 + callback(step,timer): 回调step值,计步器timer,可自行通过window.clearInterval(timer)结束计步器; + t: 计步时长,传0则直接回调end值;不传则默认300ms + rate: 周期;不传则默认30ms计步一次 + * */ +MeScroll.prototype.getStep = function(star, end, callback, t, rate) { + let diff = end - star; // 差值 + if (t === 0 || diff === 0) { + callback && callback(end); + return; + } + t = t || 300; // 时长 300ms + rate = rate || 30; // 周期 30ms + let count = t / rate; // 次数 + let step = diff / count; // 步长 + let i = 0; // 计数 + let timer = setInterval(function() { + if (i < count - 1) { + star += step; + callback && callback(star, timer); + i++; + } else { + callback && callback(end, timer); // 最后一次直接设置end,避免计算误差 + clearInterval(timer); + } + }, rate); +} + +/* 滚动容器的高度 */ +MeScroll.prototype.getClientHeight = function(isReal) { + let h = this.clientHeight || 0 + if (h === 0 && isReal !== true) { // 未获取到容器的高度,可临时取body的高度 (可能会有误差) + h = this.getBodyHeight() + } + return h +} +MeScroll.prototype.setClientHeight = function(h) { + this.clientHeight = h; +} + +/* 滚动内容的高度 */ +MeScroll.prototype.getScrollHeight = function() { + return this.scrollHeight || 0; +} +MeScroll.prototype.setScrollHeight = function(h) { + this.scrollHeight = h; +} + +/* body的高度 */ +MeScroll.prototype.getBodyHeight = function() { + return this.bodyHeight || 0; +} +MeScroll.prototype.setBodyHeight = function(h) { + this.bodyHeight = h; +} + +/* 阻止浏览器默认滚动事件 */ +MeScroll.prototype.preventDefault = function(e) { + // 小程序不支持e.preventDefault, 已在wxs中禁止 + // app的bounce只能通过配置pages.json的style.app-plus.bounce为"none"来禁止, 或使用renderjs禁止 + // cancelable:是否可以被禁用; defaultPrevented:是否已经被禁用 + if (e && e.cancelable && !e.defaultPrevented) e.preventDefault() +} \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-uni.vue b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-uni.vue new file mode 100644 index 00000000..cb5d0265 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mescroll-uni.vue @@ -0,0 +1,480 @@ + + + + + + + + + + + + + + + diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mixins/mescroll-comp.js b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mixins/mescroll-comp.js new file mode 100644 index 00000000..abe7cd7f --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mixins/mescroll-comp.js @@ -0,0 +1,47 @@ +/** + * mescroll-body写在子组件时,需通过mescroll的mixins补充子组件缺少的生命周期 + */ +const MescrollCompMixin = { + // 因为子组件无onPageScroll和onReachBottom的页面生命周期,需在页面传递进到子组件 (一级) + onPageScroll(e) { + this.handlePageScroll(e) + }, + onReachBottom() { + this.handleReachBottom() + }, + // 当down的native: true时, 还需传递此方法进到子组件 + onPullDownRefresh(){ + this.handlePullDownRefresh() + }, + data() { + return { + mescroll: { // mescroll-body写在子子子...组件的情况 (多级) + onPageScroll: e=>{ + this.handlePageScroll(e) + }, + onReachBottom: ()=>{ + this.handleReachBottom() + }, + onPullDownRefresh: ()=>{ + this.handlePullDownRefresh() + } + } + } + }, + methods:{ + handlePageScroll(e){ + let item = this.$refs["mescrollItem"]; + if(item && item.mescroll) item.mescroll.onPageScroll(e); + }, + handleReachBottom(){ + let item = this.$refs["mescrollItem"]; + if(item && item.mescroll) item.mescroll.onReachBottom(); + }, + handlePullDownRefresh(){ + let item = this.$refs["mescrollItem"]; + if(item && item.mescroll) item.mescroll.onPullDownRefresh(); + } + } +} + +export default MescrollCompMixin; diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mixins/mescroll-more-item.js b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mixins/mescroll-more-item.js new file mode 100644 index 00000000..96ca9bff --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mixins/mescroll-more-item.js @@ -0,0 +1,57 @@ +/** + * mescroll-more-item的mixins, 仅在多个 mescroll-body 写在子组件时使用 (参考 mescroll-more 案例) + */ +const MescrollMoreItemMixin = { + // 支付宝小程序不支持props的mixin,需写在具体的页面中 + // #ifndef MP-ALIPAY || MP-DINGTALK + props:{ + i: Number, // 每个tab页的专属下标 + index: { // 当前tab的下标 + type: Number, + default(){ + return 0 + } + } + }, + // #endif + data() { + return { + downOption:{ + auto:false // 不自动加载 + }, + upOption:{ + auto:false // 不自动加载 + }, + isInit: false // 当前tab是否已初始化 + } + }, + watch:{ + // 监听下标的变化 + index(val){ + if (this.i === val && !this.isInit) this.mescrollTrigger() + } + }, + methods: { + // mescroll组件初始化的回调,可获取到mescroll对象 (覆盖mescroll-mixins.js的mescrollInit, 为了标记isInit) + mescrollInit(mescroll) { + this.mescroll = mescroll; + // 自动加载当前tab的数据 + if(this.i === this.index){ + this.mescrollTrigger() + } + }, + // 主动触发加载 + mescrollTrigger(){ + this.isInit = true; // 标记为true + if (this.mescroll) { + if (this.mescroll.optDown.use) { + this.mescroll.triggerDownScroll(); + } else{ + this.mescroll.triggerUpScroll(); + } + } + } + } +} + +export default MescrollMoreItemMixin; diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mixins/mescroll-more.js b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mixins/mescroll-more.js new file mode 100644 index 00000000..16b47d89 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/mixins/mescroll-more.js @@ -0,0 +1,77 @@ +/** + * mescroll-body写在子组件时, 需通过mescroll的mixins补充子组件缺少的生命周期 + */ +const MescrollMoreMixin = { + data() { + return { + tabIndex: 0, // 当前tab下标 + mescroll: { // mescroll-body写在子子子...组件的情况 (多级) + onPageScroll: e=>{ + this.handlePageScroll(e) + }, + onReachBottom: ()=>{ + this.handleReachBottom() + }, + onPullDownRefresh: ()=>{ + this.handlePullDownRefresh() + } + } + } + }, + // 因为子组件无onPageScroll和onReachBottom的页面生命周期,需在页面传递进到子组件 + onPageScroll(e) { + this.handlePageScroll(e) + }, + onReachBottom() { + this.handleReachBottom() + }, + // 当down的native: true时, 还需传递此方法进到子组件 + onPullDownRefresh(){ + this.handlePullDownRefresh() + }, + methods:{ + handlePageScroll(e){ + let mescroll = this.getMescroll(this.tabIndex); + mescroll && mescroll.onPageScroll(e); + }, + handleReachBottom(){ + let mescroll = this.getMescroll(this.tabIndex); + mescroll && mescroll.onReachBottom(); + }, + handlePullDownRefresh(){ + let mescroll = this.getMescroll(this.tabIndex); + mescroll && mescroll.onPullDownRefresh(); + }, + // 根据下标获取对应子组件的mescroll + getMescroll(i){ + if(!this.mescrollItems) this.mescrollItems = []; + if(!this.mescrollItems[i]) { + // v-for中的refs + let vForItem = this.$refs["mescrollItem"]; + if(vForItem){ + this.mescrollItems[i] = vForItem[i] + }else{ + // 普通的refs,不可重复 + this.mescrollItems[i] = this.$refs["mescrollItem"+i]; + } + } + let item = this.mescrollItems[i] + return item ? item.mescroll : null + }, + // 切换tab,恢复滚动条位置 + tabChange(i){ + let mescroll = this.getMescroll(i); + if(mescroll){ + // 恢复上次滚动条的位置 + let y = mescroll.getScrollTop() + mescroll.scrollTo(y, 0) + // 再次恢复上次滚动条的位置, 确保元素已渲染 + setTimeout(()=>{ + mescroll.scrollTo(y, 0) + },30) + } + } + } +} + +export default MescrollMoreMixin; diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/wxs/mixins.js b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/wxs/mixins.js new file mode 100644 index 00000000..34ffa3c2 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/wxs/mixins.js @@ -0,0 +1,109 @@ +// 定义在wxs (含renderjs) 逻辑层的数据和方法, 与视图层相互通信 +const WxsMixin = { + data() { + return { + // 传入wxs视图层的数据 (响应式) + wxsProp: { + optDown:{}, // 下拉刷新的配置 + scrollTop:0, // 滚动条的距离 + bodyHeight:0, // body的高度 + isDownScrolling:false, // 是否正在下拉刷新中 + isUpScrolling:false, // 是否正在上拉加载中 + isScrollBody:true, // 是否为mescroll-body滚动 + isUpBoth:true, // 上拉加载时,是否同时可以下拉刷新 + t: 0 // 数据更新的标记 (只有数据更新了,才会触发wxs的Observer) + }, + + // 标记调用wxs视图层的方法 + callProp: { + callType: '', // 方法名 + t: 0 // 数据更新的标记 (只有数据更新了,才会触发wxs的Observer) + }, + + // 不用wxs的平台使用此处的wxsBiz对象,抹平wxs的写法 (微信小程序和APP使用的wxsBiz对象是./wxs/wxs.wxs) + // #ifndef MP-WEIXIN || MP-QQ || APP-PLUS || H5 + wxsBiz: { + //注册列表touchstart事件,用于下拉刷新 + touchstartEvent: e=> { + this.mescroll.touchstartEvent(e); + }, + //注册列表touchmove事件,用于下拉刷新 + touchmoveEvent: e=> { + this.mescroll.touchmoveEvent(e); + }, + //注册列表touchend事件,用于下拉刷新 + touchendEvent: e=> { + this.mescroll.touchendEvent(e); + }, + propObserver(){}, // 抹平wxs的写法 + callObserver(){} // 抹平wxs的写法 + }, + // #endif + + // 不用renderjs的平台使用此处的renderBiz对象,抹平renderjs的写法 (app 和 h5 使用的renderBiz对象是./wxs/renderjs.js) + // #ifndef APP-PLUS || H5 + renderBiz: { + propObserver(){} // 抹平renderjs的写法 + } + // #endif + } + }, + methods: { + // wxs视图层调用逻辑层的回调 + wxsCall(msg){ + if(msg.type === 'setWxsProp'){ + // 更新wxsProp数据 (值改变才触发更新) + this.wxsProp = { + optDown: this.mescroll.optDown, + scrollTop: this.mescroll.getScrollTop(), + bodyHeight: this.mescroll.getBodyHeight(), + isDownScrolling: this.mescroll.isDownScrolling, + isUpScrolling: this.mescroll.isUpScrolling, + isUpBoth: this.mescroll.optUp.isBoth, + isScrollBody:this.mescroll.isScrollBody, + t: Date.now() + } + }else if(msg.type === 'setLoadType'){ + // 设置inOffset,outOffset的状态 + this.downLoadType = msg.downLoadType + // 状态挂载到mescroll对象, 以便在其他组件中使用, 比如中 + this.$set(this.mescroll, 'downLoadType', this.downLoadType) + // 重置是否加载成功的状态 + this.$set(this.mescroll, 'isDownEndSuccess', null) + }else if(msg.type === 'triggerDownScroll'){ + // 主动触发下拉刷新 + this.mescroll.triggerDownScroll(); + }else if(msg.type === 'endDownScroll'){ + // 结束下拉刷新 + this.mescroll.endDownScroll(); + }else if(msg.type === 'triggerUpScroll'){ + // 主动触发上拉加载 + this.mescroll.triggerUpScroll(true); + } + } + }, + mounted() { + // #ifdef MP-WEIXIN || MP-QQ || APP-PLUS || H5 + // 配置主动触发wxs显示加载进度的回调 + this.mescroll.optDown.afterLoading = ()=>{ + this.callProp = {callType: "showLoading", t: Date.now()} // 触发wxs的方法 (值改变才触发更新) + } + // 配置主动触发wxs隐藏加载进度的回调 + this.mescroll.optDown.afterEndDownScroll = ()=>{ + this.callProp = {callType: "endDownScroll", t: Date.now()} // 触发wxs的方法 (值改变才触发更新) + let delay = 300 + (this.mescroll.optDown.beforeEndDelay || 0) + setTimeout(()=>{ + if(this.downLoadType === 4 || this.downLoadType === 0){ + this.callProp = {callType: "clearTransform", t: Date.now()} // 触发wxs的方法 (值改变才触发更新) + } + // 状态挂载到mescroll对象, 以便在其他组件中使用, 比如中 + this.$set(this.mescroll, 'downLoadType', this.downLoadType) + }, delay) + } + // 初始化wxs的数据 + this.wxsCall({type: 'setWxsProp'}) + // #endif + } +} + +export default WxsMixin; diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/wxs/renderjs.js b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/wxs/renderjs.js new file mode 100644 index 00000000..6cd13019 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/wxs/renderjs.js @@ -0,0 +1,92 @@ +// 使用renderjs直接操作window对象,实现动态控制app和h5的bounce +// bounce: iOS橡皮筋,Android半月弧,h5浏览器下拉背景等效果 (下拉刷新时禁止) +// https://uniapp.dcloud.io/frame?id=renderjs + +// 与wxs的me实例一致 +var me = {} + +// 初始化window对象的touch事件 (仅初始化一次) +if(window && !window.$mescrollRenderInit){ + window.$mescrollRenderInit = true + + + window.addEventListener('touchstart', function(e){ + if (me.disabled()) return; + me.startPoint = me.getPoint(e); // 记录起点 + }, {passive: true}) + + + window.addEventListener('touchmove', function(e){ + if (me.disabled()) return; + if (me.getScrollTop() > 0) return; // 需在顶部下拉,才禁止bounce + + var curPoint = me.getPoint(e); // 当前点 + var moveY = curPoint.y - me.startPoint.y; // 和起点比,移动的距离,大于0向下拉,小于0向上拉 + // 向下拉 + if (moveY > 0) { + // 可下拉的条件 + if (!me.isDownScrolling && !me.optDown.isLock && (!me.isUpScrolling || (me.isUpScrolling && me.isUpBoth))) { + + // 只有touch在mescroll的view上面,才禁止bounce + var el = e.target; + var isMescrollTouch = false; + while (el && el.tagName && el.tagName !== 'UNI-PAGE-BODY' && el.tagName != "BODY") { + var cls = el.classList; + if (cls && cls.contains('mescroll-render-touch')) { + isMescrollTouch = true + break; + } + el = el.parentNode; // 继续检查其父元素 + } + // 禁止bounce (不会对swiper和iOS侧滑返回造成影响) + if (isMescrollTouch && e.cancelable && !e.defaultPrevented) e.preventDefault(); + } + } + }, {passive: false}) +} + +/* 获取滚动条的位置 */ +me.getScrollTop = function() { + return me.scrollTop || document.documentElement.scrollTop || document.body.scrollTop || 0 +} + +/* 是否禁用下拉刷新 */ +me.disabled = function(){ + return !me.optDown || !me.optDown.use || me.optDown.native +} + +/* 根据点击滑动事件获取第一个手指的坐标 */ +me.getPoint = function(e) { + if (!e) { + return {x: 0,y: 0} + } + if (e.touches && e.touches[0]) { + return {x: e.touches[0].pageX,y: e.touches[0].pageY} + } else if (e.changedTouches && e.changedTouches[0]) { + return {x: e.changedTouches[0].pageX,y: e.changedTouches[0].pageY} + } else { + return {x: e.clientX,y: e.clientY} + } +} + +/** + * 监听逻辑层数据的变化 (实时更新数据) + */ +function propObserver(wxsProp) { + me.optDown = wxsProp.optDown + me.scrollTop = wxsProp.scrollTop + me.isDownScrolling = wxsProp.isDownScrolling + me.isUpScrolling = wxsProp.isUpScrolling + me.isUpBoth = wxsProp.isUpBoth +} + +/* 导出模块 */ +const renderBiz = { + data() { + return { + propObserver: propObserver, + } + } +} + +export default renderBiz; \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/wxs/wxs.wxs b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/wxs/wxs.wxs new file mode 100644 index 00000000..4af4201b --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/components/mescroll-uni/wxs/wxs.wxs @@ -0,0 +1,269 @@ +// 使用wxs处理交互动画, 提高性能, 同时避免小程序bounce对下拉刷新的影响 +// https://uniapp.dcloud.io/frame?id=wxs +// https://developers.weixin.qq.com/miniprogram/dev/framework/view/interactive-animation.html + +// 模拟mescroll实例, 与mescroll.js的写法尽量保持一致 +var me = {} + +// ------ 自定义下拉刷新动画 start ------ + +/* 下拉过程中的回调,滑动过程一直在执行 (rate<1为inOffset; rate>1为outOffset) */ +me.onMoving = function (ins, rate, downHight){ + ins.requestAnimationFrame(function () { + ins.selectComponent('.mescroll-wxs-content').setStyle({ + 'will-change': 'transform', // 可解决下拉过程中, image和swiper脱离文档流的问题 + 'transform': 'translateY(' + downHight + 'px)', + 'transition': '' + }) + // 环形进度条 + var progress = ins.selectComponent('.mescroll-wxs-progress') + progress && progress.setStyle({transform: 'rotate(' + 360 * rate + 'deg)'}) + }) +} + +/* 显示下拉刷新进度 */ +me.showLoading = function (ins){ + me.downHight = me.optDown.offset + ins.requestAnimationFrame(function () { + ins.selectComponent('.mescroll-wxs-content').setStyle({ + 'will-change': 'auto', + 'transform': 'translateY(' + me.downHight + 'px)', + 'transition': 'transform 300ms' + }) + }) +} + +/* 结束下拉 */ +me.endDownScroll = function (ins){ + me.downHight = 0; + me.isDownScrolling = false; + ins.requestAnimationFrame(function () { + ins.selectComponent('.mescroll-wxs-content').setStyle({ + 'will-change': 'auto', + 'transform': 'translateY(0)', // 不可以写空串,否则scroll-view渲染不完整 (延时350ms会调clearTransform置空) + 'transition': 'transform 300ms' + }) + }) +} + +/* 结束下拉动画执行完毕后, 清除transform和transition, 避免对列表内容样式造成影响, 如: h5的list-msg示例下拉进度条漏出来等 */ +me.clearTransform = function (ins){ + ins.requestAnimationFrame(function () { + ins.selectComponent('.mescroll-wxs-content').setStyle({ + 'will-change': '', + 'transform': '', + 'transition': '' + }) + }) +} + +// ------ 自定义下拉刷新动画 end ------ + +/** + * 监听逻辑层数据的变化 (实时更新数据) + */ +function propObserver(wxsProp) { + if(!wxsProp) return + me.optDown = wxsProp.optDown + me.scrollTop = wxsProp.scrollTop + me.bodyHeight = wxsProp.bodyHeight + me.isDownScrolling = wxsProp.isDownScrolling + me.isUpScrolling = wxsProp.isUpScrolling + me.isUpBoth = wxsProp.isUpBoth + me.isScrollBody = wxsProp.isScrollBody + me.startTop = wxsProp.scrollTop // 及时更新touchstart触发的startTop, 避免scroll-view快速惯性滚动到顶部取值不准确 +} + +/** + * 监听逻辑层数据的变化 (调用wxs的方法) + */ +function callObserver(callProp, oldValue, ins) { + if (me.disabled()) return; + if(callProp.callType){ + // 逻辑层(App Service)的style已失效,需在视图层(Webview)设置style + if(callProp.callType === 'showLoading'){ + me.showLoading(ins) + }else if(callProp.callType === 'endDownScroll'){ + me.endDownScroll(ins) + }else if(callProp.callType === 'clearTransform'){ + me.clearTransform(ins) + } + } +} + +/** + * touch事件 + */ +function touchstartEvent(e, ins) { + me.downHight = 0; // 下拉的距离 + me.startPoint = me.getPoint(e); // 记录起点 + me.startTop = me.getScrollTop(); // 记录此时的滚动条位置 + me.startAngle = 0; // 初始角度 + me.lastPoint = me.startPoint; // 重置上次move的点 + me.maxTouchmoveY = me.getBodyHeight() - me.optDown.bottomOffset; // 手指触摸的最大范围(写在touchstart避免body获取高度为0的情况) + me.inTouchend = false; // 标记不是touchend + + me.callMethod(ins, {type: 'setWxsProp'}) // 同步更新wxsProp的数据 (小程序是异步的,可能touchmove先执行,才到propObserver; h5和app是同步) +} + +function touchmoveEvent(e, ins) { + var isPrevent = true // false表示不往上冒泡,相当于调用了同时调用了stopPropagation和preventDefault (对小程序生效, h5和app无效) + + if (me.disabled()) return isPrevent; + + var scrollTop = me.getScrollTop(); // 当前滚动条的距离 + var curPoint = me.getPoint(e); // 当前点 + + var moveY = curPoint.y - me.startPoint.y; // 和起点比,移动的距离,大于0向下拉,小于0向上拉 + + // 向下拉 && 在顶部 + // mescroll-body,直接判定在顶部即可 + // scroll-view在滚动时不会触发touchmove,当触顶/底/左/右时,才会触发touchmove + // scroll-view滚动到顶部时,scrollTop不一定为0,也有可能大于0; 在iOS的APP中scrollTop可能为负数,不一定和startTop相等 + if (moveY > 0 && ( + (me.isScrollBody && scrollTop <= 0) + || + (!me.isScrollBody && (scrollTop <= 0 || (scrollTop <= me.optDown.startTop && scrollTop === me.startTop)) ) + )) { + // 可下拉的条件 + if (!me.inTouchend && !me.isDownScrolling && !me.optDown.isLock && (!me.isUpScrolling || (me.isUpScrolling && + me.isUpBoth))) { + + // 下拉的角度是否在配置的范围内 + if(!me.startAngle) me.startAngle = me.getAngle(me.lastPoint, curPoint); // 两点之间的角度,区间 [0,90] + if (me.startAngle < me.optDown.minAngle) return isPrevent; // 如果小于配置的角度,则不往下执行下拉刷新 + + // 如果手指的位置超过配置的距离,则提前结束下拉,避免Webview嵌套导致touchend无法触发 + if (me.maxTouchmoveY > 0 && curPoint.y >= me.maxTouchmoveY) { + me.inTouchend = true; // 标记执行touchend + touchendEvent(e, ins); // 提前触发touchend + return isPrevent; + } + + isPrevent = false // 小程序是return false + + var diff = curPoint.y - me.lastPoint.y; // 和上次比,移动的距离 (大于0向下,小于0向上) + + // 下拉距离 < 指定距离 + if (me.downHight < me.optDown.offset) { + if (me.movetype !== 1) { + me.movetype = 1; // 加入标记,保证只执行一次 + // me.optDown.inOffset && me.optDown.inOffset(me); // 进入指定距离范围内那一刻的回调,只执行一次 + me.callMethod(ins, {type: 'setLoadType', downLoadType: 1}) + me.isMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来 + } + me.downHight += diff * me.optDown.inOffsetRate; // 越往下,高度变化越小 + + // 指定距离 <= 下拉距离 + } else { + if (me.movetype !== 2) { + me.movetype = 2; // 加入标记,保证只执行一次 + // me.optDown.outOffset && me.optDown.outOffset(me); // 下拉超过指定距离那一刻的回调,只执行一次 + me.callMethod(ins, {type: 'setLoadType', downLoadType: 2}) + me.isMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来 + } + if (diff > 0) { // 向下拉 + me.downHight += diff * me.optDown.outOffsetRate; // 越往下,高度变化越小 + } else { // 向上收 + me.downHight += diff; // 向上收回高度,则向上滑多少收多少高度 + } + } + + me.downHight = Math.round(me.downHight) // 取整 + var rate = me.downHight / me.optDown.offset; // 下拉区域当前高度与指定距离的比值 + // me.optDown.onMoving && me.optDown.onMoving(me, rate, me.downHight); // 下拉过程中的回调,一直在执行 + me.onMoving(ins, rate, me.downHight) + } + } + + me.lastPoint = curPoint; // 记录本次移动的点 + + return isPrevent // false表示不往上冒泡,相当于调用了同时调用了stopPropagation和preventDefault (对小程序生效, h5和app无效) +} + +function touchendEvent(e, ins) { + // 如果下拉区域高度已改变,则需重置回来 + if (me.isMoveDown) { + if (me.downHight >= me.optDown.offset) { + // 符合触发刷新的条件 + me.downHight = me.optDown.offset; // 更新下拉区域高度 + // me.triggerDownScroll(); + me.callMethod(ins, {type: 'triggerDownScroll'}) + } else { + // 不符合的话 则重置 + me.downHight = 0; + // me.optDown.endDownScroll && me.optDown.endDownScroll(me); + me.callMethod(ins, {type: 'endDownScroll'}) + } + me.movetype = 0; + me.isMoveDown = false; + } else if (!me.isScrollBody && me.getScrollTop() === me.startTop) { // scroll-view到顶/左/右/底的滑动事件 + var isScrollUp = me.getPoint(e).y - me.startPoint.y < 0; // 和起点比,移动的距离,大于0向下拉,小于0向上拉 + // 上滑 + if (isScrollUp) { + // 需检查滑动的角度 + var angle = me.getAngle(me.getPoint(e), me.startPoint); // 两点之间的角度,区间 [0,90] + if (angle > 80) { + // 检查并触发上拉 + // me.triggerUpScroll(true); + me.callMethod(ins, {type: 'triggerUpScroll'}) + } + } + } + me.callMethod(ins, {type: 'setWxsProp'}) // 同步更新wxsProp的数据 (小程序是异步的,可能touchmove先执行,才到propObserver; h5和app是同步) +} + +/* 是否禁用下拉刷新 */ +me.disabled = function(){ + return !me.optDown || !me.optDown.use || me.optDown.native +} + +/* 根据点击滑动事件获取第一个手指的坐标 */ +me.getPoint = function(e) { + if (!e) { + return {x: 0,y: 0} + } + if (e.touches && e.touches[0]) { + return {x: e.touches[0].pageX,y: e.touches[0].pageY} + } else if (e.changedTouches && e.changedTouches[0]) { + return {x: e.changedTouches[0].pageX,y: e.changedTouches[0].pageY} + } else { + return {x: e.clientX,y: e.clientY} + } +} + +/* 计算两点之间的角度: 区间 [0,90]*/ +me.getAngle = function (p1, p2) { + var x = Math.abs(p1.x - p2.x); + var y = Math.abs(p1.y - p2.y); + var z = Math.sqrt(x * x + y * y); + var angle = 0; + if (z !== 0) { + angle = Math.asin(y / z) / Math.PI * 180; + } + return angle +} + +/* 获取滚动条的位置 */ +me.getScrollTop = function() { + return me.scrollTop || 0 +} + +/* 获取body的高度 */ +me.getBodyHeight = function() { + return me.bodyHeight || 0; +} + +/* 调用逻辑层的方法 */ +me.callMethod = function(ins, param) { + if(ins) ins.callMethod('wxsCall', param) +} + +/* 导出模块 */ +module.exports = { + propObserver: propObserver, + callObserver: callObserver, + touchstartEvent: touchstartEvent, + touchmoveEvent: touchmoveEvent, + touchendEvent: touchendEvent +} \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-mescroll/hooks/useMescroll.js b/smart-app/src/uni_modules/uni-mescroll/hooks/useMescroll.js new file mode 100644 index 00000000..ef91cd13 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/hooks/useMescroll.js @@ -0,0 +1,66 @@ +// 小程序无法在hook中使用页面级别生命周期,需单独传入: https://ask.dcloud.net.cn/question/161173 +// import { onPageScroll, onReachBottom, onPullDownRefresh} from '@dcloudio/uni-app'; + +/** + * 初始化mescroll, 相当于vue2的mescroll-mixins.js文件 (mescroll-body 和 mescroll-uni 通用) + * mescroll-body需传入onPageScroll, onReachBottom + * mescroll-uni无需传onPageScroll, onReachBottom + * 当down.native为true时,需传入onPullDownRefresh + */ +function useMescroll(onPageScroll, onReachBottom, onPullDownRefresh){ + // mescroll实例对象 + let mescroll = null; + + // mescroll组件初始化的回调,可获取到mescroll对象 + const mescrollInit = (e)=> { + mescroll = e; + } + + // 获取mescroll对象, mescrollInit执行之后会有值, 生命周期created中会有值 + const getMescroll = ()=>{ + return mescroll + } + + // 下拉刷新的回调 (mixin默认resetUpScroll) + const downCallback = ()=> { + if(mescroll.optUp.use){ + mescroll.resetUpScroll() + }else{ + setTimeout(()=>{ + mescroll.endSuccess(); + }, 500) + } + } + + // 上拉加载的回调 + const upCallback = ()=> { + // mixin默认延时500自动结束加载 + setTimeout(()=>{ + mescroll.endErr(); + }, 500) + } + + // 注册系统自带的下拉刷新 (配置down.native为true时生效, 还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例) + onPullDownRefresh && onPullDownRefresh(() => { + mescroll && mescroll.onPullDownRefresh(); + }) + + // 注册列表滚动事件,用于判定在顶部可下拉刷新,在指定位置可显示隐藏回到顶部按钮 (此方法为页面生命周期,无法在子组件中触发, 仅在mescroll-body生效) + onPageScroll && onPageScroll(e=>{ + mescroll && mescroll.onPageScroll(e); + }) + + // 注册滚动到底部的事件,用于上拉加载 (此方法为页面生命周期,无法在子组件中触发, 仅在mescroll-body生效) + onReachBottom && onReachBottom(()=>{ + mescroll && mescroll.onReachBottom(); + }) + + return { + getMescroll, + mescrollInit, + downCallback, + upCallback + } +} + +export default useMescroll \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-mescroll/hooks/useMescrollComp.js b/smart-app/src/uni_modules/uni-mescroll/hooks/useMescrollComp.js new file mode 100644 index 00000000..3b83847e --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/hooks/useMescrollComp.js @@ -0,0 +1,56 @@ +import { ref } from 'vue'; + +// 小程序无法在hook中使用页面级别生命周期,需单独传入: https://ask.dcloud.net.cn/question/161173 +// import { onPageScroll, onReachBottom, onPullDownRefresh} from '@dcloudio/uni-app'; + +/** + * mescroll-body写在子组件时,需通过useMescrollComp补充子组件缺少的生命周期, 相当于vue2的mescroll-comp.js文件 + * 必须传入onPageScroll, onReachBottom + * 当down.native为true时,需传入onPullDownRefresh + */ +function useMescrollComp(onPageScroll, onReachBottom, onPullDownRefresh){ + // 因为子组件无onPageScroll和onReachBottom的页面生命周期,需在页面传递进到子组件 + onPageScroll(e=>{ + handlePageScroll(e) + }) + + onReachBottom(()=>{ + handleReachBottom() + }) + + // 当down的native: true时, 还需传递此方法进到子组件 + onPullDownRefresh && onPullDownRefresh(()=>{ + handlePullDownRefresh() + }) + + const mescrollItem = ref(null) + + const handlePageScroll = (e)=>{ + const mescroll = getMescroll() + mescroll && mescroll.onPageScroll(e); + } + + const handleReachBottom = ()=>{ + const mescroll = getMescroll() + mescroll && mescroll.onReachBottom(); + } + + const handlePullDownRefresh = ()=>{ + const mescroll = getMescroll() + mescroll && mescroll.onPullDownRefresh(); + } + + const getMescroll = ()=>{ + if(mescrollItem.value && mescrollItem.value.getMescroll){ + return mescrollItem.value.getMescroll() + } + return null + } + + return { + mescrollItem, + getMescroll + } +} + +export default useMescrollComp \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-mescroll/hooks/useMescrollMore.js b/smart-app/src/uni_modules/uni-mescroll/hooks/useMescrollMore.js new file mode 100644 index 00000000..f9a3cd0e --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/hooks/useMescrollMore.js @@ -0,0 +1,69 @@ +import { ref } from 'vue'; + +// 小程序无法在hook中使用页面级别生命周期,需单独传入: https://ask.dcloud.net.cn/question/161173 +// import { onPageScroll, onReachBottom, onPullDownRefresh} from '@dcloudio/uni-app'; + +/** mescroll-more示例写在子组件时,需通过useMescrollMore补充子组件缺少的生命周期, 相当于vue2的mescroll-more.js文件 */ +function useMescrollMore(mescrollItems, onPageScroll, onReachBottom, onPullDownRefresh){ + // 当前tab下标 + const tabIndex = ref(0) + + // 因为子组件无onPageScroll和onReachBottom的页面生命周期,需在页面传递进到子组件 + onPageScroll && onPageScroll(e=>{ + handlePageScroll(e) + }) + + onReachBottom && onReachBottom(()=>{ + handleReachBottom() + }) + + // 当down的native: true时, 还需传递此方法进到子组件 + onPullDownRefresh && onPullDownRefresh(()=>{ + handlePullDownRefresh() + }) + + const handlePageScroll = (e)=>{ + let mescroll = getMescroll(tabIndex.value); + mescroll && mescroll.onPageScroll(e); + } + const handleReachBottom = ()=>{ + let mescroll = getMescroll(tabIndex.value); + mescroll && mescroll.onReachBottom(); + } + + const handlePullDownRefresh = ()=>{ + let mescroll = getMescroll(tabIndex.value); + mescroll && mescroll.onPullDownRefresh(); + } + + // 根据下标获取对应子组件的mescroll + const getMescroll = (i)=>{ + if (mescrollItems && mescrollItems[i]) { + return mescrollItems[i].value.getMescroll() + } else{ + return null + } + } + + // 切换tab,恢复滚动条位置 + const scrollToLastY = ()=>{ + let mescroll = getMescroll(tabIndex.value); + if(mescroll){ + // 恢复上次滚动条的位置 + let y = mescroll.getScrollTop() + mescroll.scrollTo(y, 0) + // 再次恢复上次滚动条的位置, 确保元素已渲染 + setTimeout(()=>{ + mescroll.scrollTo(y, 0) + },20) + } + } + + return { + tabIndex, + getMescroll, + scrollToLastY + } +} + +export default useMescrollMore \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-mescroll/package.json b/smart-app/src/uni_modules/uni-mescroll/package.json new file mode 100644 index 00000000..ef37663b --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/package.json @@ -0,0 +1,76 @@ +{ + "id": "mescroll-uni", + "displayName": "高性能下拉刷新上拉加载组件 支持vue3 setup", + "version": "1.3.8", + "description": "wxs+renderjs实现, 支持原生页面和局部区域滚动, 支持vue3 script setup的写法", + "keywords": [ + "下拉刷新", + "上拉加载", + "翻页分页", + "wxs", + "setup" +], + "repository": "https://github.com/mescroll/mescroll", +"engines": { + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/mescroll-uni", + "type": "component-vue" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y" + }, + "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" + } + } + } + } +} \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-mescroll/readme.md b/smart-app/src/uni_modules/uni-mescroll/readme.md new file mode 100644 index 00000000..4bce1789 --- /dev/null +++ b/smart-app/src/uni_modules/uni-mescroll/readme.md @@ -0,0 +1,45 @@ +## mescroll --【wxs+renderjs实现】高性能的下拉刷新上拉加载组件 +1. mescroll的uni版本 是专门用在uni-app的下拉刷新和上拉加载的组件 + +2. mescroll的uni版本 继承了mescroll.js的实用功能: 自动处理分页, 自动控制无数据, 空布局提示, 回到顶部按钮 .. + +3. mescroll的uni版本 丰富的案例, 自由灵活的api, 超详细的注释, 可让您快速自定义真正属于自己的下拉上拉组件 + +
+ + +## 最新文档(1.3.8版本): https://www.mescroll.com/uni.html +2023-03-26 by 小瑾同学 (文档可能会有缓存,建议打开时刷新一下) + + +## 1.3.5版本已调整为[uni_modules](https://uniapp.dcloud.io/uni_modules) +uni_modules版本的mescroll-body 和 mescroll-empty 支持 [easycom规范](https://uniapp.dcloud.io/collocation/pages?id=easycom) +所以 main.js 无需再为mescroll-body注册全局组件 +所以个别页面要单独使用 mescroll-empty , 也无需手动注册 +#### 1.3.5以前的用户升级为uni_modules版本: +``` +1. 删除原来的 @/components/mescroll-uni 组件 +2. 删除 main.js 注册的 mescroll 组件 +3. 从插件市场导入最新mescroll组件 (1.3.5+uni_modules版本) +4. 全局搜索 '@/components/mescroll-uni/' 替换为 '@/uni_modules/mescroll-uni/components/mescroll-uni/' +5. mescroll-empty遵循easycom规范, 若某些页面单独使用 'mescroll-empty.vue', 可删除手动导入的代码 +``` + +## 近期已更新优化的内容: +1. 新增vue3 script setup的示例 +2. 新增`入门极简`示例, 国际化`mescroll-i18n.vue`示例, 轮播吸顶菜单`mescroll-swiper-sticky.vue`示例 +3. 新增 "局部区域滚动" 的案例: mescroll-body-part.vue 和 mescroll-uni-part.vue +4. 新增 me-video 视频组件, 解决APP端视频下拉悬浮错位的问题, 参考 mescroll-options.vue 示例 +5. 新增 me-tabs 组件,tabs支持水平滑动; 优化mescroll-more和mescroll-swiper的案例, 顶部tab支持水平滑动 +6. 吸顶悬浮提供了原生sticky和监听滚动条实现的示例: sticky.vue 和 sticky-scroll.vue (推荐使用sticky样式实现) +7. mescroll.scrollTo(y)的y支持css选择器, 包括跨自定义组件的后代选择器, 支持滚动到子组件的view (参考 mescroll-options.vue) +8. topbar 顶部是否预留状态栏的高度, 默认false; 还可支持设置状态栏背景: 如 '#ffff00', 'url(xxx) 0 0/100% 100%', 'linear-gradient(xx)' +9. down.bgColor 和 up.bgColor 加载区域的背景,不仅支持色值, 而且还是支持背景图和渐变: 如 'url(xxx) 0 0/100% 100%', 'linear-gradient(xx)' +10. topbar,bgColor支持一行代码定义background: [https://www.runoob.com/cssref/css3-pr-background.html](https://www.runoob.com/cssref/css3-pr-background.html) +
+
+查看更多 ... + +
+ +#### mescroll不支持nvue,也暂无支持的计划哈,so sorry~ \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-scss/changelog.md b/smart-app/src/uni_modules/uni-scss/changelog.md new file mode 100644 index 00000000..b863bb0f --- /dev/null +++ b/smart-app/src/uni_modules/uni-scss/changelog.md @@ -0,0 +1,8 @@ +## 1.0.3(2022-01-21) +- 优化 组件示例 +## 1.0.2(2021-11-22) +- 修复 / 符号在 vue 不同版本兼容问题引起的报错问题 +## 1.0.1(2021-11-22) +- 修复 vue3中scss语法兼容问题 +## 1.0.0(2021-11-18) +- init diff --git a/smart-app/src/uni_modules/uni-scss/index.scss b/smart-app/src/uni_modules/uni-scss/index.scss new file mode 100644 index 00000000..1744a5f9 --- /dev/null +++ b/smart-app/src/uni_modules/uni-scss/index.scss @@ -0,0 +1 @@ +@import './styles/index.scss'; diff --git a/smart-app/src/uni_modules/uni-scss/package.json b/smart-app/src/uni_modules/uni-scss/package.json new file mode 100644 index 00000000..7cc0ccb7 --- /dev/null +++ b/smart-app/src/uni_modules/uni-scss/package.json @@ -0,0 +1,82 @@ +{ + "id": "uni-scss", + "displayName": "uni-scss 辅助样式", + "version": "1.0.3", + "description": "uni-sass是uni-ui提供的一套全局样式 ,通过一些简单的类名和sass变量,实现简单的页面布局操作,比如颜色、边距、圆角等。", + "keywords": [ + "uni-scss", + "uni-ui", + "辅助样式" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "category": [ + "JS SDK", + "通用 SDK" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "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" + }, + "快应用": { + "华为": "n", + "联盟": "n" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/smart-app/src/uni_modules/uni-scss/readme.md b/smart-app/src/uni_modules/uni-scss/readme.md new file mode 100644 index 00000000..b7d1c25f --- /dev/null +++ b/smart-app/src/uni_modules/uni-scss/readme.md @@ -0,0 +1,4 @@ +`uni-sass` 是 `uni-ui`提供的一套全局样式 ,通过一些简单的类名和`sass`变量,实现简单的页面布局操作,比如颜色、边距、圆角等。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-sass) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-scss/styles/index.scss b/smart-app/src/uni_modules/uni-scss/styles/index.scss new file mode 100644 index 00000000..ffac4fec --- /dev/null +++ b/smart-app/src/uni_modules/uni-scss/styles/index.scss @@ -0,0 +1,7 @@ +@import './setting/_variables.scss'; +@import './setting/_border.scss'; +@import './setting/_color.scss'; +@import './setting/_space.scss'; +@import './setting/_radius.scss'; +@import './setting/_text.scss'; +@import './setting/_styles.scss'; diff --git a/smart-app/src/uni_modules/uni-scss/styles/setting/_border.scss b/smart-app/src/uni_modules/uni-scss/styles/setting/_border.scss new file mode 100644 index 00000000..12a11c32 --- /dev/null +++ b/smart-app/src/uni_modules/uni-scss/styles/setting/_border.scss @@ -0,0 +1,3 @@ +.uni-border { + border: 1px $uni-border-1 solid; +} \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-scss/styles/setting/_color.scss b/smart-app/src/uni_modules/uni-scss/styles/setting/_color.scss new file mode 100644 index 00000000..1ededd94 --- /dev/null +++ b/smart-app/src/uni_modules/uni-scss/styles/setting/_color.scss @@ -0,0 +1,66 @@ + +// TODO 暂时不需要 class ,需要用户使用变量实现 ,如果使用类名其实并不推荐 +// @mixin get-styles($k,$c) { +// @if $k == size or $k == weight{ +// font-#{$k}:#{$c} +// }@else{ +// #{$k}:#{$c} +// } +// } +$uni-ui-color:( + // 主色 + primary: $uni-primary, + primary-disable: $uni-primary-disable, + primary-light: $uni-primary-light, + // 辅助色 + success: $uni-success, + success-disable: $uni-success-disable, + success-light: $uni-success-light, + warning: $uni-warning, + warning-disable: $uni-warning-disable, + warning-light: $uni-warning-light, + error: $uni-error, + error-disable: $uni-error-disable, + error-light: $uni-error-light, + info: $uni-info, + info-disable: $uni-info-disable, + info-light: $uni-info-light, + // 中性色 + main-color: $uni-main-color, + base-color: $uni-base-color, + secondary-color: $uni-secondary-color, + extra-color: $uni-extra-color, + // 背景色 + bg-color: $uni-bg-color, + // 边框颜色 + border-1: $uni-border-1, + border-2: $uni-border-2, + border-3: $uni-border-3, + border-4: $uni-border-4, + // 黑色 + black:$uni-black, + // 白色 + white:$uni-white, + // 透明 + transparent:$uni-transparent +) !default; +@each $key, $child in $uni-ui-color { + .uni-#{"" + $key} { + color: $child; + } + .uni-#{"" + $key}-bg { + background-color: $child; + } +} +.uni-shadow-sm { + box-shadow: $uni-shadow-sm; +} +.uni-shadow-base { + box-shadow: $uni-shadow-base; +} +.uni-shadow-lg { + box-shadow: $uni-shadow-lg; +} +.uni-mask { + background-color:$uni-mask; +} diff --git a/smart-app/src/uni_modules/uni-scss/styles/setting/_radius.scss b/smart-app/src/uni_modules/uni-scss/styles/setting/_radius.scss new file mode 100644 index 00000000..9a0428bb --- /dev/null +++ b/smart-app/src/uni_modules/uni-scss/styles/setting/_radius.scss @@ -0,0 +1,55 @@ +@mixin radius($r,$d:null ,$important: false){ + $radius-value:map-get($uni-radius, $r) if($important, !important, null); + // Key exists within the $uni-radius variable + @if (map-has-key($uni-radius, $r) and $d){ + @if $d == t { + border-top-left-radius:$radius-value; + border-top-right-radius:$radius-value; + }@else if $d == r { + border-top-right-radius:$radius-value; + border-bottom-right-radius:$radius-value; + }@else if $d == b { + border-bottom-left-radius:$radius-value; + border-bottom-right-radius:$radius-value; + }@else if $d == l { + border-top-left-radius:$radius-value; + border-bottom-left-radius:$radius-value; + }@else if $d == tl { + border-top-left-radius:$radius-value; + }@else if $d == tr { + border-top-right-radius:$radius-value; + }@else if $d == br { + border-bottom-right-radius:$radius-value; + }@else if $d == bl { + border-bottom-left-radius:$radius-value; + } + }@else{ + border-radius:$radius-value; + } +} + +@each $key, $child in $uni-radius { + @if($key){ + .uni-radius-#{"" + $key} { + @include radius($key) + } + }@else{ + .uni-radius { + @include radius($key) + } + } +} + +@each $direction in t, r, b, l,tl, tr, br, bl { + @each $key, $child in $uni-radius { + @if($key){ + .uni-radius-#{"" + $direction}-#{"" + $key} { + @include radius($key,$direction,false) + } + }@else{ + .uni-radius-#{$direction} { + @include radius($key,$direction,false) + } + } + } +} diff --git a/smart-app/src/uni_modules/uni-scss/styles/setting/_space.scss b/smart-app/src/uni_modules/uni-scss/styles/setting/_space.scss new file mode 100644 index 00000000..3c895289 --- /dev/null +++ b/smart-app/src/uni_modules/uni-scss/styles/setting/_space.scss @@ -0,0 +1,56 @@ + +@mixin fn($space,$direction,$size,$n) { + @if $n { + #{$space}-#{$direction}: #{$size*$uni-space-root}px + } @else { + #{$space}-#{$direction}: #{-$size*$uni-space-root}px + } +} +@mixin get-styles($direction,$i,$space,$n){ + @if $direction == t { + @include fn($space, top,$i,$n); + } + @if $direction == r { + @include fn($space, right,$i,$n); + } + @if $direction == b { + @include fn($space, bottom,$i,$n); + } + @if $direction == l { + @include fn($space, left,$i,$n); + } + @if $direction == x { + @include fn($space, left,$i,$n); + @include fn($space, right,$i,$n); + } + @if $direction == y { + @include fn($space, top,$i,$n); + @include fn($space, bottom,$i,$n); + } + @if $direction == a { + @if $n { + #{$space}:#{$i*$uni-space-root}px; + } @else { + #{$space}:#{-$i*$uni-space-root}px; + } + } +} + +@each $orientation in m,p { + $space: margin; + @if $orientation == m { + $space: margin; + } @else { + $space: padding; + } + @for $i from 0 through 16 { + @each $direction in t, r, b, l, x, y, a { + .uni-#{$orientation}#{$direction}-#{$i} { + @include get-styles($direction,$i,$space,true); + } + .uni-#{$orientation}#{$direction}-n#{$i} { + @include get-styles($direction,$i,$space,false); + } + } + } +} \ No newline at end of file diff --git a/smart-app/src/uni_modules/uni-scss/styles/setting/_styles.scss b/smart-app/src/uni_modules/uni-scss/styles/setting/_styles.scss new file mode 100644 index 00000000..689afec6 --- /dev/null +++ b/smart-app/src/uni_modules/uni-scss/styles/setting/_styles.scss @@ -0,0 +1,167 @@ +/* #ifndef APP-NVUE */ + +$-color-white:#fff; +$-color-black:#000; +@mixin base-style($color) { + color: #fff; + background-color: $color; + border-color: mix($-color-black, $color, 8%); + &:not([hover-class]):active { + background: mix($-color-black, $color, 10%); + border-color: mix($-color-black, $color, 20%); + color: $-color-white; + outline: none; + } +} +@mixin is-color($color) { + @include base-style($color); + &[loading] { + @include base-style($color); + &::before { + margin-right:5px; + } + } + &[disabled] { + &, + &[loading], + &:not([hover-class]):active { + color: $-color-white; + border-color: mix(darken($color,10%), $-color-white); + background-color: mix($color, $-color-white); + } + } + +} +@mixin base-plain-style($color) { + color:$color; + background-color: mix($-color-white, $color, 90%); + border-color: mix($-color-white, $color, 70%); + &:not([hover-class]):active { + background: mix($-color-white, $color, 80%); + color: $color; + outline: none; + border-color: mix($-color-white, $color, 50%); + } +} +@mixin is-plain($color){ + &[plain] { + @include base-plain-style($color); + &[loading] { + @include base-plain-style($color); + &::before { + margin-right:5px; + } + } + &[disabled] { + &, + &:active { + color: mix($-color-white, $color, 40%); + background-color: mix($-color-white, $color, 90%); + border-color: mix($-color-white, $color, 80%); + } + } + } +} + + +.uni-btn { + margin: 5px; + color: #393939; + border:1px solid #ccc; + font-size: 16px; + font-weight: 200; + background-color: #F9F9F9; + // TODO 暂时处理边框隐藏一边的问题 + overflow: visible; + &::after{ + border: none; + } + + &:not([type]),&[type=default] { + color: #999; + &[loading] { + background: none; + &::before { + margin-right:5px; + } + } + + + + &[disabled]{ + color: mix($-color-white, #999, 60%); + &, + &[loading], + &:active { + color: mix($-color-white, #999, 60%); + background-color: mix($-color-white,$-color-black , 98%); + border-color: mix($-color-white, #999, 85%); + } + } + + &[plain] { + color: #999; + background: none; + border-color: $uni-border-1; + &:not([hover-class]):active { + background: none; + color: mix($-color-white, $-color-black, 80%); + border-color: mix($-color-white, $-color-black, 90%); + outline: none; + } + &[disabled]{ + &, + &[loading], + &:active { + background: none; + color: mix($-color-white, #999, 60%); + border-color: mix($-color-white, #999, 85%); + } + } + } + } + + &:not([hover-class]):active { + color: mix($-color-white, $-color-black, 50%); + } + + &[size=mini] { + font-size: 16px; + font-weight: 200; + border-radius: 8px; + } + + + + &.uni-btn-small { + font-size: 14px; + } + &.uni-btn-mini { + font-size: 12px; + } + + &.uni-btn-radius { + border-radius: 999px; + } + &[type=primary] { + @include is-color($uni-primary); + @include is-plain($uni-primary) + } + &[type=success] { + @include is-color($uni-success); + @include is-plain($uni-success) + } + &[type=error] { + @include is-color($uni-error); + @include is-plain($uni-error) + } + &[type=warning] { + @include is-color($uni-warning); + @include is-plain($uni-warning) + } + &[type=info] { + @include is-color($uni-info); + @include is-plain($uni-info) + } +} +/* #endif */ diff --git a/smart-app/src/uni_modules/uni-scss/styles/setting/_text.scss b/smart-app/src/uni_modules/uni-scss/styles/setting/_text.scss new file mode 100644 index 00000000..a34d08f3 --- /dev/null +++ b/smart-app/src/uni_modules/uni-scss/styles/setting/_text.scss @@ -0,0 +1,24 @@ +@mixin get-styles($k,$c) { + @if $k == size or $k == weight{ + font-#{$k}:#{$c} + }@else{ + #{$k}:#{$c} + } +} + +@each $key, $child in $uni-headings { + /* #ifndef APP-NVUE */ + .uni-#{$key} { + @each $k, $c in $child { + @include get-styles($k,$c) + } + } + /* #endif */ + /* #ifdef APP-NVUE */ + .container .uni-#{$key} { + @each $k, $c in $child { + @include get-styles($k,$c) + } + } + /* #endif */ +} diff --git a/smart-app/src/uni_modules/uni-scss/styles/setting/_variables.scss b/smart-app/src/uni_modules/uni-scss/styles/setting/_variables.scss new file mode 100644 index 00000000..557d3d7c --- /dev/null +++ b/smart-app/src/uni_modules/uni-scss/styles/setting/_variables.scss @@ -0,0 +1,146 @@ +// @use "sass:math"; +@import '../tools/functions.scss'; +// 间距基础倍数 +$uni-space-root: 2 !default; +// 边框半径默认值 +$uni-radius-root:5px !default; +$uni-radius: () !default; +// 边框半径断点 +$uni-radius: map-deep-merge( + ( + 0: 0, + // TODO 当前版本暂时不支持 sm 属性 + // 'sm': math.div($uni-radius-root, 2), + null: $uni-radius-root, + 'lg': $uni-radius-root * 2, + 'xl': $uni-radius-root * 6, + 'pill': 9999px, + 'circle': 50% + ), + $uni-radius +); +// 字体家族 +$body-font-family: 'Roboto', sans-serif !default; +// 文本 +$heading-font-family: $body-font-family !default; +$uni-headings: () !default; +$letterSpacing: -0.01562em; +$uni-headings: map-deep-merge( + ( + 'h1': ( + size: 32px, + weight: 300, + line-height: 50px, + // letter-spacing:-0.01562em + ), + 'h2': ( + size: 28px, + weight: 300, + line-height: 40px, + // letter-spacing: -0.00833em + ), + 'h3': ( + size: 24px, + weight: 400, + line-height: 32px, + // letter-spacing: normal + ), + 'h4': ( + size: 20px, + weight: 400, + line-height: 30px, + // letter-spacing: 0.00735em + ), + 'h5': ( + size: 16px, + weight: 400, + line-height: 24px, + // letter-spacing: normal + ), + 'h6': ( + size: 14px, + weight: 500, + line-height: 18px, + // letter-spacing: 0.0125em + ), + 'subtitle': ( + size: 12px, + weight: 400, + line-height: 20px, + // letter-spacing: 0.00937em + ), + 'body': ( + font-size: 14px, + font-weight: 400, + line-height: 22px, + // letter-spacing: 0.03125em + ), + 'caption': ( + 'size': 12px, + 'weight': 400, + 'line-height': 20px, + // 'letter-spacing': 0.03333em, + // 'text-transform': false + ) + ), + $uni-headings +); + + + +// 主色 +$uni-primary: #2979ff !default; +$uni-primary-disable:lighten($uni-primary,20%) !default; +$uni-primary-light: lighten($uni-primary,25%) !default; + +// 辅助色 +// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。 +$uni-success: #18bc37 !default; +$uni-success-disable:lighten($uni-success,20%) !default; +$uni-success-light: lighten($uni-success,25%) !default; + +$uni-warning: #f3a73f !default; +$uni-warning-disable:lighten($uni-warning,20%) !default; +$uni-warning-light: lighten($uni-warning,25%) !default; + +$uni-error: #e43d33 !default; +$uni-error-disable:lighten($uni-error,20%) !default; +$uni-error-light: lighten($uni-error,25%) !default; + +$uni-info: #8f939c !default; +$uni-info-disable:lighten($uni-info,20%) !default; +$uni-info-light: lighten($uni-info,25%) !default; + +// 中性色 +// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。 +$uni-main-color: #3a3a3a !default; // 主要文字 +$uni-base-color: #6a6a6a !default; // 常规文字 +$uni-secondary-color: #909399 !default; // 次要文字 +$uni-extra-color: #c7c7c7 !default; // 辅助说明 + +// 边框颜色 +$uni-border-1: #F0F0F0 !default; +$uni-border-2: #EDEDED !default; +$uni-border-3: #DCDCDC !default; +$uni-border-4: #B9B9B9 !default; + +// 常规色 +$uni-black: #000000 !default; +$uni-white: #ffffff !default; +$uni-transparent: rgba($color: #000000, $alpha: 0) !default; + +// 背景色 +$uni-bg-color: #f7f7f7 !default; + +/* 水平间距 */ +$uni-spacing-sm: 8px !default; +$uni-spacing-base: 15px !default; +$uni-spacing-lg: 30px !default; + +// 阴影 +$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5) !default; +$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default; +$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5) !default; + +// 蒙版 +$uni-mask: rgba($color: #000000, $alpha: 0.4) !default; diff --git a/smart-app/src/uni_modules/uni-scss/styles/tools/functions.scss b/smart-app/src/uni_modules/uni-scss/styles/tools/functions.scss new file mode 100644 index 00000000..ac6f63e5 --- /dev/null +++ b/smart-app/src/uni_modules/uni-scss/styles/tools/functions.scss @@ -0,0 +1,19 @@ +// 合并 map +@function map-deep-merge($parent-map, $child-map){ + $result: $parent-map; + @each $key, $child in $child-map { + $parent-has-key: map-has-key($result, $key); + $parent-value: map-get($result, $key); + $parent-type: type-of($parent-value); + $child-type: type-of($child); + $parent-is-map: $parent-type == map; + $child-is-map: $child-type == map; + + @if (not $parent-has-key) or ($parent-type != $child-type) or (not ($parent-is-map and $child-is-map)){ + $result: map-merge($result, ( $key: $child )); + }@else { + $result: map-merge($result, ( $key: map-deep-merge($parent-value, $child) )); + } + } + @return $result; +}; diff --git a/smart-app/src/uni_modules/uni-scss/theme.scss b/smart-app/src/uni_modules/uni-scss/theme.scss new file mode 100644 index 00000000..80ee62f7 --- /dev/null +++ b/smart-app/src/uni_modules/uni-scss/theme.scss @@ -0,0 +1,31 @@ +// 间距基础倍数 +$uni-space-root: 2; +// 边框半径默认值 +$uni-radius-root:5px; +// 主色 +$uni-primary: #2979ff; +// 辅助色 +$uni-success: #4cd964; +// 警告色 +$uni-warning: #f0ad4e; +// 错误色 +$uni-error: #dd524d; +// 描述色 +$uni-info: #909399; +// 中性色 +$uni-main-color: #303133; +$uni-base-color: #606266; +$uni-secondary-color: #909399; +$uni-extra-color: #C0C4CC; +// 背景色 +$uni-bg-color: #f5f5f5; +// 边框颜色 +$uni-border-1: #DCDFE6; +$uni-border-2: #E4E7ED; +$uni-border-3: #EBEEF5; +$uni-border-4: #F2F6FC; + +// 常规色 +$uni-black: #000000; +$uni-white: #ffffff; +$uni-transparent: rgba($color: #000000, $alpha: 0); diff --git a/smart-app/src/uni_modules/uni-scss/variables.scss b/smart-app/src/uni_modules/uni-scss/variables.scss new file mode 100644 index 00000000..1c062d42 --- /dev/null +++ b/smart-app/src/uni_modules/uni-scss/variables.scss @@ -0,0 +1,62 @@ +@import './styles/setting/_variables.scss'; +// 间距基础倍数 +$uni-space-root: 2; +// 边框半径默认值 +$uni-radius-root:5px; + +// 主色 +$uni-primary: #2979ff; +$uni-primary-disable:mix(#fff,$uni-primary,50%); +$uni-primary-light: mix(#fff,$uni-primary,80%); + +// 辅助色 +// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。 +$uni-success: #18bc37; +$uni-success-disable:mix(#fff,$uni-success,50%); +$uni-success-light: mix(#fff,$uni-success,80%); + +$uni-warning: #f3a73f; +$uni-warning-disable:mix(#fff,$uni-warning,50%); +$uni-warning-light: mix(#fff,$uni-warning,80%); + +$uni-error: #e43d33; +$uni-error-disable:mix(#fff,$uni-error,50%); +$uni-error-light: mix(#fff,$uni-error,80%); + +$uni-info: #8f939c; +$uni-info-disable:mix(#fff,$uni-info,50%); +$uni-info-light: mix(#fff,$uni-info,80%); + +// 中性色 +// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。 +$uni-main-color: #3a3a3a; // 主要文字 +$uni-base-color: #6a6a6a; // 常规文字 +$uni-secondary-color: #909399; // 次要文字 +$uni-extra-color: #c7c7c7; // 辅助说明 + +// 边框颜色 +$uni-border-1: #F0F0F0; +$uni-border-2: #EDEDED; +$uni-border-3: #DCDCDC; +$uni-border-4: #B9B9B9; + +// 常规色 +$uni-black: #000000; +$uni-white: #ffffff; +$uni-transparent: rgba($color: #000000, $alpha: 0); + +// 背景色 +$uni-bg-color: #f7f7f7; + +/* 水平间距 */ +$uni-spacing-sm: 8px; +$uni-spacing-base: 15px; +$uni-spacing-lg: 30px; + +// 阴影 +$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5); +$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2); +$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5); + +// 蒙版 +$uni-mask: rgba($color: #000000, $alpha: 0.4); diff --git a/smart-app/src/uni_modules/y-tabs/components/css/index.scss b/smart-app/src/uni_modules/y-tabs/components/css/index.scss new file mode 100644 index 00000000..579d60b2 --- /dev/null +++ b/smart-app/src/uni_modules/y-tabs/components/css/index.scss @@ -0,0 +1,464 @@ +.y-tabs { + position: relative; + display: block; + + // 标签栏垂直方位下的根容器样式 + &.is-vertical { + display: flex; + flex-wrap: nowrap; + flex-direction: row; + justify-content: flex-end; + flex: 1; + + // 垂直时标签栏scroll-view的子项垂直排列 + .y-tabs__scroll { + flex-direction: column; + } + } + + // 区域滚动下的滚动导航 + &.is-areaScroll.is-scrollNav { + display: flex; + height: 100vh; + flex-direction: column; + + // 标签栏不收缩 + .y-tabs__wrap { + flex-shrink: 0; + } + + .y-tabs__track, + .y-tabs__content-scrollview { + height: 100%; + } + } + + // 区域滚动下的侧边栏导航 + &.is-areaScroll.is-sidebarNav { + display: flex; + height: 100vh; + flex-direction: row; + + .y-tabs__scroll { + height: 100%; + } + + // 标签栏不收缩 + .y-tabs__wrap { + flex-shrink: 0; + } + + .y-tabs__track, + .y-tabs__content-scrollview { + height: 100%; + } + } +} + +// 依赖元素 +.y-tabs__depend { + position: absolute; + top: 0; + left: 0; + height: 1px; //必须保证有高度,否则observer无效 + width: 100%; +} + +// 透明标签栏所需的依赖元素 +.y-tabs__depend--transparent { + position: absolute; + top: 0; + left: 0; + height: 1px; //必须保证有高度,否则observer无效 + width: 1px; +} + +// 模拟标签栏吸顶时设置offset时距屏幕顶部的元素 +.y-tabs__depend--offset { + position: fixed; + top: 0; + left: 0; + z-index: -1; + height: 1px; +} + +// 标签栏占位元素 +.y-tabs__placeholder { + position: relative; +} + +// 标签垂直展示且吸顶时,标签栏占位元素不伸缩 +.y-tabs.is-fixed.is-vertical .y-tabs__placeholder { + flex-shrink: 0; +} + +// 文字省略 +.y-tabs__ellipsis { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +// 导航区域包裹层 +.y-tabs__wrap { + position: relative; + display: flex; + align-items: center; + overflow: hidden; + visibility: visible; + background: #fff; + touch-action: none; + + // 标签栏垂直展示时包裹层样式 + &.is-vertical { + width: 100px; + display: flex; + flex-direction: column; + flex-shrink: 0; + } + + // 粘性定位布局下的导航区域包裹层 + &.is-fixed { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 99; + } + + // 标签垂直展示且吸顶时,给定bottom,否则scroll-view不会滚动 + &.is-fixed.is-vertical { + bottom: 0; + } + + // 透明的导航区域包裹层 + &.is-transparent { + background: rgba(255, 255, 255, 0); + } + + // 标签栏水平时按钮风格的包裹层 + &.is-button:not(.is-vertical), + &.is-line-button:not(.is-vertical) { + padding: 0 8px; + } +} + +// scroll-view组件样式 +.y-tabs__scroll { + position: relative; + width: 100%; + white-space: nowrap; // 使用横向滚动时,需要给添加white-space: nowrap;样式 + flex-direction: row; +} + +// 条件编译不放在样式中,vue3无效 + +// H5、APP端去滚动条 +// 小程序端会报:Some selectors are not allowed in component wxss, including tag name selectors, ID selectors, and attribute selectors. +/* #ifdef H5 || APP */ +.y-tabs__scroll ::-webkit-scrollbar { + display: none; + width: 0; + height: 0; + -webkit-appearance: none; + background: transparent; + color: transparent; +} +/* #endif */ + +// IOS 13 以下的系统,当滚动区域设置了-webkit-overflow-scrolling: touch;时(必须设置,否者几乎无法滚动),::-webkit-scrollbar 相关属性会失效,iOS 13 已经修复了此Bug。 +// 小程序端: 去除 scroll-view 组件的滚动条 +/* #ifndef H5 || APP */ +::-webkit-scrollbar { + display: none; + width: 0; + height: 0; + -webkit-appearance: none; + background: transparent; + color: transparent; +} +/* #endif */ + +// 导航区域 +.y-tabs__nav { + position: relative; + box-sizing: border-box; + user-select: none; + flex: 1; + display: flex; + + &.is-shrink{ + display: inline-flex; + } + + // 卡片风格 + &.is-card { + margin: 6px 16px; + border-radius: 4px; + box-sizing: border-box; + border: 1px solid #0022ab; + } + + // 标签栏垂直时导航区域样式 + &.is-vertical { + flex-direction: column; + height: auto; + + .y-tab { + flex: unset; + } + } + + // 标签左侧、右侧的补充区域 + &-left, + &-right { + position: relative; + display: inline-flex; + white-space: nowrap; + } +} + +// 导航标签 +.y-tab { + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + height: 40px; + font-size: 28rpx; + color: #646566; + text-align: center; + padding: 0 4px; + flex: 1; + cursor: pointer; + // webkit的css扩展:1、-webkit-tap-highlight-color:这个属性是用于设定元素在移动设备(如Adnroid、iOS)上被触发点击事件时,响应的背景框的颜色。有事件监听的元素被点击的时候会被高亮显示,比如我的android上表现为一个蓝框加上半透明的背景 + -webkit-tap-highlight-color: transparent; + // transition-duration: 0.2s; + // transition-property: background; + flex-shrink: 0; + z-index: 2; + + // 选中状态 + &.is-active { + color: #323233; + font-weight: 500; + } + + // 禁用状态 + &.is-disabled { + color: #c8c9cc !important; + cursor: not-allowed; + } + + // 收缩布局 + &.is-shrink { + flex: none; + padding: 0 8px; + } + + //卡片风格 + &.is-card { + height: 28px; + line-height: 28px; + } +} + +// 标题区域 +.y-tab__title { + overflow: hidden; + display: flex; + align-items: center; + height: inherit; +} + +// 标题区域垂直排列 +.y-tab__title--top, +.y-tab__title--bottom { + flex-direction: column; +} + +// 标题文字 +.y-tab__text { + position: relative; + display: block; + line-height: 1.2; + order: 2; + white-space: nowrap; //字节会设置white-space:normal +} + +// 标签垂直展示时,未达到文字超出隐藏的条件时 +.y-tabs__nav.is-vertical .y-tab__text:not(.y-tabs__ellipsis) { + white-space: normal; +} + +// 使用order排序 +.y-tab__text--left, +.y-tab__text--top { + order: 0; +} + +// 标题图标/图片包裹层 +.y-tab__icons { + display: flex; + align-items: center; + order: 1; + z-index: 1; +} + +//标题图片 +.y-tab__image { + width: 20px; + height: 20px; +} + +// 右上角信息区域 +.y-tab__info { + display: inline-flex; + position: relative; + + &--dot, + &--badge { + display: inline-block; + position: absolute; + top: 0; + left: 0; + box-sizing: border-box; + background-color: #e53935; + transform-origin: 100%; + } + + // 小红点 + &--dot { + width: 6px; + height: 6px; + border-radius: 100%; + transform: translate(0%, -180%); + } + + // 徽标 + &--badge { + line-height: 13px; + min-width: 18px; + border-radius: 18px; + padding: 0 2px; + transform: translate(0%, -120%); + font-size: 18rpx; + font-weight: 500; + text-align: center; + color: #fff; + } +} + +// 底部条滑块 +.y-tabs__bar { + position: absolute; + display: inline-flex; + left: 0; + z-index: 1; + + width: 20px; + height: 3px; + border-radius: 3px; + background-color: #0022ab; + + // line风格的滑块 + &.is-line { + z-index: 2; //z-index与y-tab一样,避免被遮挡 + + // 标签水平展示时 + &:not(.is-vertical) { + bottom: 3px; + width: 20px; + height: 3px; + border-radius: 3px; + } + + // 标签垂直展示时 + &.is-vertical { + top: 0; + left: 3px; + width: 3px; + height: 20px; + border-radius: 3px; + } + } + + // button、line-button风格的滑块 + &.is-button, + &.is-line-button { + // top: 0; + justify-content: center; + align-items: center; + border-radius: 26px; + + // 标签水平展示时 + &:not(.is-vertical) { + height: calc(100% - 8px); + bottom: 4px; + } + + // 标签垂直展示时 + &.is-vertical { + width: calc(100% - 8px); + height: calc(100% - 8px); + } + } + + // 线性按钮风格的滑块 + &.is-line-button { + background-color: transparent; + border: 2rpx solid transparent; + } +} + +// 标签内容 +.y-tabs__content { + display: block; + position: relative; + overflow: hidden; //会导致uni-data-select无法撑开显示下拉选项,最好给pane中的内容设置一个高度(如果包裹select的父元素都没有设置relative,则不会裁剪absolute属性的元素) + // 标签栏垂直展示,内容减去标签栏默认宽度 + &.is-vertical { + width: 100%; + } +} +// 标签内容的滑动轨道容器 +.y-tabs__track { + position: relative; + display: flex; + width: 100%; + will-change: left; + + // 滚动导航模式下内容卡片垂直排列 + &.is-scrollspy { + flex-direction: column; + } +} + +// 标签内容卡片 +.y-tab__pane { + flex-shrink: 0; + box-sizing: border-box; + width: 100%; + height: 0; + position: relative; + flex-direction: row; + display: block; + visibility: visible; + + // 选中时 + &.is-active { + height: auto; + } + // 滚动导航 + &.is-scrollspy { + height: auto; + } +} +.y-tab__pane--wrap { + position: relative; +} +// 区域滚动下的标签内容scroll-view +.y-tabs__content-scrollview { + flex-direction: column; +} diff --git a/smart-app/src/uni_modules/y-tabs/components/js/const.js b/smart-app/src/uni_modules/y-tabs/components/js/const.js new file mode 100644 index 00000000..854d8faf --- /dev/null +++ b/smart-app/src/uni_modules/y-tabs/components/js/const.js @@ -0,0 +1,194 @@ +// styleIsolation:组件样式隔离方式,具体配置选项参见:微信小程序自定义组件的样式 +// 自定义组件 JSON 中的 styleIsolation 选项从基础库版本 2.10.1 开始支持。它支持以下取值: +// isolated 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响(一般情况下的默认值); +// apply-shared 表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面; +// shared 表示页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中指定的样式也会影响页面和其他设置了 apply-shared 或 shared 的自定义组件。(这个选项在插件中不可用。) + +const options = { + styleIsolation: 'shared', + virtualHost: true // [微信小程序、支付宝小程序(默认值为 true)] 将自定义节点设置成虚拟的,更加接近Vue组件的表现。我们不希望自定义组件的这个节点本身可以设置样式、响应 flex 布局等,而是希望自定义组件内部的第一层节点能够响应 flex 布局或者样式由自定义组件本身完全决定 + // 微信(可以使用virtualHost配置)/QQ/百度/字节跳动这四家小程序,自定义组件在渲染时会比App/H5端多一级节点,导致flex无效,是否考虑在组件上增加class控制 +} + + + +const emits = [ + "input", + 'update:modelValue', // 更新v-model绑定的变量 + 'click', //点击标签时触发 回调参数:name:标识符,title:标题 + 'change', //当前激活的标签改变时触发 回调参数:name:标识符,title:标题 + 'disabled', //点击被禁用的标签时触发 回调参数:name:标识符,title:标题 + 'rendered', //标签内容首次渲染时触发(仅在开启延迟渲染后触发) 回调参数:name:标识符,title:标题 + 'sticky-change', //吸顶时触发,仅在 sticky 模式下生效 回调参数:name:标识符,title:标题 + 'loaded', //组件内部初始化完成后调用 回调参数:{ isFixed: 是否吸顶 } + 'slide-change', //内容页滑动时触发(仅barAnimateMode为linear、worm、worm-ease时有效) 回调参数:{ dx:滑动距离; rate:当前滑动长度占滑动区域的比例;targetIndex:目标下标;} + 'slide-end' //内容页滑动结束时触发(仅barAnimateMode为linear、worm、worm-ease时有效) 回调参数:{ targetIndex:目标下标;} +]; + +const props = { + // v-model绑定属性,绑定当前选中标签的标识符(标签的下标) + value: { + type: [Number, String], + default: 0, + }, + modelValue: { + type: [Number, String], + default: 0, + }, + // 样式风格类型,可选值为 text、card、button、line-button + type: { + type: String, + default: "line", + validator(value) { + return ['line', 'text', 'card', 'button', 'line-button'].includes(value) + } + }, + color: { + type: [String, null], + default: "#0022AB" + }, //标签主题色, 默认值为"#0022AB" + background: { + type: [String, null], + // default: "#fff" + }, //标签栏背景色,默认值为"#fff" + // 标签栏样式 + wrapStyle: { + type: [Object, null], + default: () => {} + }, + // 标签栏的展示方位,可选值:vertical。 + direction: { + type: String, + default: "horizontal", + validator(value) { + return ['horizontal', 'vertical'].includes(value) + } + }, + titleActiveColor: String, //标题选中态颜色 + titleInactiveColor: String, //标题默认态颜色 + // 是否开启左侧收缩布局,开启后,所有的标签会向左侧收缩对齐。 + shrink: { + type: Boolean, + default: false + }, + + // 动画时间,单位秒,默认为0.3s。仅支持type为line、button、line-button的滑块切换动画,切换标签内容时的转场动画、滚动导航下的内容定位动画。 + duration: { + type: [Number, String], + default: 0.2, + }, + // 滑块宽度,默认单位为px, 支持数字、rpx、vh、vw等单位及calc() 函数。 仅支持type为line、button、line-button。 + // 标签栏水平/垂直展示时,type为line,宽度默认为20px/3px, 而type为button、line-button时,宽度默认为选中标签宽度-8px。 + barWidth: [Number, String], //inherit:继承tab的宽高 + // 滑块高度,默认单位为px, 支持数字、rpx、vh、vw等单位及calc() 函数。 仅支持type为line、button、line-button。 + // 标签栏水平/垂直展示时,type为line,高度默认为3px/20px, 而type为button、line-button时,宽度默认为选中标签高度-8px。 + barHeight: [Number, String], + //滑块样式,仅支持type为line、button、line-button。 + barStyle: Object, + // 滑动切换tab内容时滑块的动画模式,默认值为line,即切换tab时滑块宽度保持不变,线性运动。可选值为worm(毛毛虫效果)、worm-ease(毛毛虫缓动)、none(不设置)。 + // 可结合swiper组件使用,滑动效果更好。 + // 仅支持type为line。 + barAnimateMode: { + type: String, + default: "linear", + validator(value) { + return ['none', 'linear', 'worm', 'worm-ease'].includes(value); + } + }, + // 标签宽高是否动态变化 + // 表示标签切换了选中状态后宽高是否有变化,有则需要开启该属性,否则会导致滑块错位 + isDynamic: { + type: Boolean, + default: false, + }, + // 是否省略过长的标题文字。标签栏水平展示时,如果标签数量未超过滚动阈值则生效,垂直展示不限制。 + ellipsis: { + type: Boolean, + default: true, + }, + // 滚动阈值,标签数量超过阈值且总宽度超过标签栏宽度时开始横向滚动 + scrollThreshold: { + type: [Number, String], + default: 5 + }, + // 标签栏滚动时当前标签居中 + scrollToCenter: { + type: Boolean, + default: true, + }, + // 切换标签前的回调函数,返回 false 可阻止切换,支持返回 Promise + beforeChange: Function, + // 是否开启延迟渲染(首次切换到标签时才触发内容渲染) + isLazyRender: Boolean, + // 是否开启切换动画 + // 用于标签栏滚动动画、切换标签内容时的转场动画、滚动导航下的内容定位动画 + animated: { + type: Boolean, + default: true + }, + // 在滚动导航模式下,滚动到最后一个标签内容但其顶部未超过可视区域时,是否激活对应的标签项 + activeLast: { + type: Boolean, + default: false, + }, + // ---------------------------------- 用于内容区域左右滑动的配置 ---------------------------------------- + // 是否开启手势滑动切换 + swipeable: { + type: Boolean, + default: false, + }, + // 是否开启标签内容滑动时的拖动动画 + // swipeable为true时有效,建议设置is-lazy-render=false。(该属性开启时考虑给包裹内容的容器增加一个min-height,因为其他未显示的标签内容会沿用当前显示的高度,拖动切换后由于高度不一致会有回弹) + swipeAnimated: { + type: Boolean, + default: true, + }, + // 滑动切换的滑动距离阈值,单位为px;表示开启手势滑动时,横向滑动多少px切换标签内容(快速滑动时不受限制) + swipeThreshold: { + type: [Number, String], + default: 120, + }, + // ---------------------------------- 用于滚动吸顶的配置 ---------------------------------------- + // 是否使用粘性定位布局进行滚动吸顶 + sticky: Boolean, + // 粘性布局下与顶部的最小距离,单位为px + offsetTop: { + type: Number, + default: 0 + }, + // 粘性布局下标签栏的z-index值 + zIndex: { + type: Number, + default: 99 + }, + // 粘性布局的判断阈值:表示在页面滚动过程中,标签栏距屏幕顶部多少px时,触发吸顶函数进行吸顶判断 + stickyThreshold: { + type: Number, + default: 0 + }, + // 页面滚动过程中,标题栏背景色是否透明渐变 + // background属性值必须为rgba格式 + transparent: { + type: Boolean, + default: false + }, + // 标题栏背景色透明渐变的滚动距离 + transparentOffset: { + type: Number, + default: 100 + }, + // 是否开启滚动导航;该模式下,内容将会平铺展示 + // 如果标签栏垂直展示,且内容平铺展示,就为侧边栏模式 + scrollspy: Boolean, + // 滚动导航模式下,内容区域是否跟随页面滚动 + // 为true时,整体区域跟随页面而滚动,为false时,内容区域是放在scroll-view中实现的局部滚动 + pageScroll: { + type: Boolean, + default: true + }, +} +export { + options, + emits, + props, +} \ No newline at end of file diff --git a/smart-app/src/uni_modules/y-tabs/components/js/touchMixin.js b/smart-app/src/uni_modules/y-tabs/components/js/touchMixin.js new file mode 100644 index 00000000..997972a8 --- /dev/null +++ b/smart-app/src/uni_modules/y-tabs/components/js/touchMixin.js @@ -0,0 +1,75 @@ +import { getDirection, now } from "./uitls" + +export const touchMixin = { + data() { + return { + direction: '', //滑动方向 + startX: '', //开始滑动的x坐标 + startY: '', //开始滑动的y坐标 + nextIndex: -1, //下一个切换的标签下标 + moved: false, //是否为一次水平滑动 + startTimestamp: 0, + }; + }, + methods: { + touchStart(event) { + if (!this.parent.swipeable) return; + this.resetTouchStatus(); + this.startX = event.touches[0].clientX; + this.startY = event.touches[0].clientY; + this.startTimestamp = now(); + }, + touchMove(event) { + if (!this.parent.swipeable) return; + const touch = event.touches[0]; + this.deltaX = touch.clientX < 0 ? 0 : this.startX - touch.clientX; + this.deltaY = this.startY - touch.clientY; + const offsetX = Math.abs(this.deltaX); + const offsetY = Math.abs(this.deltaY); + // 当距离大于某个值时锁定方向 + if (!this.direction || (offsetX < 10 && offsetY < 10)) this.direction = getDirection(offsetX, offsetY); + + if (this.direction === "horizontal") { //水平滑动 + const { dataLen, contentWidth, currentIndex, tabs, swipeAnimated } = this.parent; + const isRight = this.deltaX < 0; //判断是否向右滑动 + + // 如果为第一页,则不允许向右滑;为最后一页,则不允许左滑 + if ((isRight && currentIndex === 0) || (!isRight && currentIndex === dataLen - 1)) return; + + this.nextIndex = currentIndex + (isRight ? -1 : 1); //下一个标签 + if (tabs[this.nextIndex]?.disabled) return; //禁用的标签不允许滑动 + + this.moved = true; //标记为一次水平滑动 + + // 改变标签内容滑动轨道样式,模拟拖动动画效果 + if (swipeAnimated) { + const offsetWidth = contentWidth * currentIndex * -1 + offsetX * (isRight ? 1 : -1); + this.parent.changeTrackStyle(true, 0, offsetWidth); + this.parent.setDx(this.deltaX, false); + } + } + }, + touchEnd() { + if (this.moved) { + // 何时可切换标签,当横向滑动距离大于设定阈值,或快速滑动(300ms内)切滑动距离大于18px时 + const deltaTime = now() - this.startTimestamp; + const distance = Math.abs(this.deltaX); + const speed = (distance / deltaTime).toFixed(4); + const isChange = speed > 0.25 || distance >= this.parent.swipeThreshold;//是否切换 + const currIndex = this.parent.currentIndex; //当前选中下标 + const targetIndex = isChange ? this.nextIndex : currIndex; //目标标签的下标 + this.parent.touchEndForPane(this.deltaX, currIndex, targetIndex, isChange); + + } + }, + // 重置触摸状态 + resetTouchStatus() { + this.direction = ''; + this.deltaX = 0; + this.deltaY = 0; + this.nextIndex = -1; + this.moved = false; + this.startTimestamp = 0; + }, + } +} \ No newline at end of file diff --git a/smart-app/src/uni_modules/y-tabs/components/js/uitls.js b/smart-app/src/uni_modules/y-tabs/components/js/uitls.js new file mode 100644 index 00000000..ee840896 --- /dev/null +++ b/smart-app/src/uni_modules/y-tabs/components/js/uitls.js @@ -0,0 +1,177 @@ +/** + * 判断传入的值是否为空 + * @param {*} val + * @returns + */ +export function isNull(val) { + if (typeof val == "boolean") { + return false; + } + if (typeof val == "number") { + return false; + } + if (val instanceof Array) { + if (val.length == 0) return true; + } else if (val instanceof Object) { + if (JSON.stringify(val) === "{}") return true; + } else { + if ( + val == "null" || + val == null || + val == "undefined" || + val == undefined || + val == "" + ) + return true; + return false; + } + return false; +} + +// 不为空 +export function isDef(val) { + return val !== undefined && val !== null; +} + +// 是否是一个数字 +export function isNumeric(val) { + return /^\d+(\.\d+)?$/.test(val); +} + +// 是一个对象 +export function isObject(val) { + return val !== null && typeof val === 'object'; +} +// 是一个字符串 +export function isString(val) { + return Object.prototype.toString.call(val) === "[object String]" +} + +// 空操作 +export function noop() {} + +// 是一个函数 +export function isFunction(val) { + return typeof val === 'function'; +} + +// 是一个promise对象 +export function isPromise(val) { + return isObject(val) && isFunction(val.then) && isFunction(val.catch); +} + + + +// 添加单位 +export function addUnit(value) { + if (!isDef(value)) { + return undefined; + } + + value = String(value); + return isNumeric(value) ? `${value}px` : value; +} + +// 调用拦截器 +export function callInterceptor(options) { + const { + interceptor, + args, + done + } = options; + + if (interceptor) { + const returnVal = interceptor(...args); + if (isPromise(returnVal)) { + returnVal.then((value) => { + if (value) done(); + }).catch(noop); + } else if (returnVal) { + done(); + } + } else { + done(); + } +} + +const rgbaRegex = /^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d*(?:\.\d+)?)\)$/; +export const getColor = function(colorStr) { + const matches = colorStr.match(rgbaRegex); + if (matches && matches.length === 5) { + return [ + matches[1], + matches[2], + matches[3], + matches[4] + ]; + } + return []; +}; + +export function toClass(classObj, ...classArray) { + const arr = Object.keys(classObj || {}).filter(key => classObj[key]) + arr.push(...classArray) + return arr.join(" ") +} + + +// 判断是水平滑动还是垂直滑动 +export function getDirection(x, y) { + if (x > y) return 'horizontal'; + if (y > x) return 'vertical'; + return ''; +} + + + +// 缓动函数 +function easingFunction(time, duration, type = "linear") { + let pos = time / duration; + let value = 0; + switch (type) { + case "easeOutCubic": + value = (Math.pow((pos - 1), 3) + 1) + break; + case "easeInOutCubic": + if ((pos /= 0.5) < 1) value = 0.5 * Math.pow(pos, 3); + else value = 0.5 * (Math.pow((pos - 2), 3) + 2); + break; + default: //linear + value = pos; + break; + } + return value; +} + +/** + * 进度函数 + * @param {Object} time 当前已经运动的时间 + * @param {Object} begin 距离的初始值 + * @param {Object} end 距离的结束值 + * @param {Object} duration 运动时长 + */ +export function progress(time, begin, end, duration, type) { + return begin + (end - begin) * easingFunction(time, duration, type); +} + + +let uid = 0; +export function getUid() { + return uid++ +} + + +const hasOwnProperty = Object.prototype.hasOwnProperty +/** + * 检查对象是否具有该属性 + * @param {*} obj 对象 + * @param {*} key 对象属性名 + * @returns + */ +export function hasOwn(obj, key) { + return hasOwnProperty.call(obj, key) +} + +export const now = Date.now || function() { + return +new Date(); +}; \ No newline at end of file diff --git a/smart-app/src/uni_modules/y-tabs/components/js/utilMixin.js b/smart-app/src/uni_modules/y-tabs/components/js/utilMixin.js new file mode 100644 index 00000000..8654bea0 --- /dev/null +++ b/smart-app/src/uni_modules/y-tabs/components/js/utilMixin.js @@ -0,0 +1,8 @@ + +export const utilMixin = function() { + return { + methods: { + + }, + } +} \ No newline at end of file diff --git a/smart-app/src/uni_modules/y-tabs/components/y-tab/y-tab.vue b/smart-app/src/uni_modules/y-tabs/components/y-tab/y-tab.vue new file mode 100644 index 00000000..5a6a82af --- /dev/null +++ b/smart-app/src/uni_modules/y-tabs/components/y-tab/y-tab.vue @@ -0,0 +1,238 @@ + + + + + diff --git a/smart-app/src/uni_modules/y-tabs/components/y-tabs/y-tabs.vue b/smart-app/src/uni_modules/y-tabs/components/y-tabs/y-tabs.vue new file mode 100644 index 00000000..121f9731 --- /dev/null +++ b/smart-app/src/uni_modules/y-tabs/components/y-tabs/y-tabs.vue @@ -0,0 +1,1363 @@ + + + diff --git a/smart-app/src/utils/str-util.js b/smart-app/src/utils/str-util.js new file mode 100644 index 00000000..6d4b59ba --- /dev/null +++ b/smart-app/src/utils/str-util.js @@ -0,0 +1,46 @@ +/* + * 字符串 相关操作 + * + * @Author: 1024创新实验室-主任:卓大 + * @Date: 2022-09-06 20:58:49 + * @Wechat: zhuda1024 + * @Email: lab1024@163.com + * @Copyright 1024创新实验室 ( https://1024lab.net ),Since 2012 + */ + +/** + * 转为 小写中划线 + */ +export function convertLowerHyphen(str) { + if (!str) { + return ''; + } + + return str + .replace(/([A-Z])/g, '-$1') + .toLowerCase() + .substring(1); +} +/** + * 转为驼峰 + */ +export function convertUpperCamel(str) { + if (!str) { + return ''; + } + + str = str.replace(/_(\w)/g, (_, letter) => letter.toUpperCase()); + // 首字母大写 + return str[0].toUpperCase() + str.substring(1); +} + +/** + * 转为驼峰 + */ +export function convertLowerCamel(str) { + if (!str) { + return ''; + } + + return str.replace(/_(\w)/g, (_, letter) => letter.toUpperCase()); +} diff --git a/smart-app/vite.config.js b/smart-app/vite.config.js new file mode 100644 index 00000000..63ae5761 --- /dev/null +++ b/smart-app/vite.config.js @@ -0,0 +1,37 @@ +import { resolve } from 'path'; +import { defineConfig } from 'vite' +import uni from '@dcloudio/vite-plugin-uni' + +const pathResolve = (dir) => { + return resolve(__dirname, '.', dir); +}; + +export default defineConfig({ + transpileDependencies:['@dcloudio/uni-ui'], + plugins: [ + uni(), + ], + root: process.cwd(), + resolve: { + alias: [ + // 绝对路径重命名:/@/xxxx => src/xxxx + { + find: /\/@\//, + replacement: pathResolve('src') + '/', + }, + { + find: /^~/, + replacement: '', + }, + ], + }, + // 发布时删除console + build: { + minify: 'terser', + terserOptions: { + compress: { + drop_console: true, + }, + }, + }, +})