commit d2f735d2f6f45ada2dece4fc4354ab1985470a5e Author: lixin Date: Thu Jan 9 16:16:11 2025 +0800 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..06d3451 --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +.DS_Store +node_modules/ +unpackage/ +dist/ + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Editor directories and files +.project +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw* + +yarn.lock +package-lock.json +pnpm-lock.yaml + + + +types/auto-imports.d.ts +types/components.d.ts diff --git a/.hbuilderx/launch.json b/.hbuilderx/launch.json new file mode 100644 index 0000000..b0d1694 --- /dev/null +++ b/.hbuilderx/launch.json @@ -0,0 +1,36 @@ +{ + // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/ + // launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数 + "version" : "0.0", + "configurations" : [ + { + "app-plus" : { + "launchtype" : "local" + }, + "default" : { + "launchtype" : "local" + }, + "h5" : { + "launchtype" : "local" + }, + "mp-alipay" : { + "launchtype" : "local" + }, + "mp-toutiao" : { + "launchtype" : "local" + }, + "mp-weixin" : { + "launchtype" : "local" + }, + "type" : "uniCloud" + }, + { + "playground" : "standard", + "type" : "uni-app:app-ios" + }, + { + "playground" : "standard", + "type" : "uni-app:app-android" + } + ] +} diff --git a/.hintrc b/.hintrc new file mode 100644 index 0000000..d5bb468 --- /dev/null +++ b/.hintrc @@ -0,0 +1,8 @@ +{ + "extends": [ + "development" + ], + "hints": { + "typescript-config/is-valid": "off" + } +} \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..5305129 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "tabWidth": 4, + "useTabs": true, + "semi": true, + "jsxBracketSameLine": true, + "singleQuote": false, + "printWidth": 100 +} diff --git a/App.vue b/App.vue new file mode 100644 index 0000000..d6cd1d8 --- /dev/null +++ b/App.vue @@ -0,0 +1,32 @@ + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..f79f067 --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +# COOL-UNI + +让你不用想太多就能开发完功能,7.0 携带 vue3、vite、ts、pinia 等众多新特性细节曝光!![文档地址](https://cool-js.com/uni/introduce.html) + +## 更快 + +- 启动快:基于 `vite`,快速的冷启动,不需要等待打包,即时的热模块更新,真正的按需编译。 + +- 开发快:`eps` 模式下,无须手动添加接口请求方法。 + +## 更强 + +内置请求、路由、文件上传、组件通信、缓存等方法及 ui 库和 hooks + +```html + +``` + +## 更细 + +全面的代码描述 diff --git a/androidPrivacy.json b/androidPrivacy.json new file mode 100644 index 0000000..0d726ca --- /dev/null +++ b/androidPrivacy.json @@ -0,0 +1,3 @@ +{ + "prompt" : "template" +} diff --git a/build/cool/eps.d.ts b/build/cool/eps.d.ts new file mode 100644 index 0000000..2c2da2a --- /dev/null +++ b/build/cool/eps.d.ts @@ -0,0 +1,1687 @@ +declare namespace Eps { + interface AppComplainEntity { + /** + * ID + */ + id?: number; + /** + * 用户ID + */ + userId?: number; + /** + * 类型 + */ + type?: number; + /** + * 联系方式 + */ + contact?: string; + /** + * 内容 + */ + content?: string; + /** + * 图片 + */ + images?: json; + /** + * 状态 0-未处理 1-已处理 + */ + status?: number; + /** + * 处理人ID + */ + handlerId?: number; + /** + * 备注 + */ + remark?: string; + /** + * 创建时间 + */ + createTime?: Date; + /** + * 更新时间 + */ + updateTime?: Date; + /** + * 任意键值 + */ + [key: string]: any; + } + + interface AppFeedbackEntity { + /** + * ID + */ + id?: number; + /** + * 用户ID + */ + userId?: number; + /** + * 联系方式 + */ + contact?: string; + /** + * 类型 + */ + type?: number; + /** + * 内容 + */ + content?: string; + /** + * 图片 + */ + images?: json; + /** + * 状态 0-未处理 1-已处理 + */ + status?: number; + /** + * 处理人ID + */ + handlerId?: number; + /** + * 备注 + */ + remark?: string; + /** + * 创建时间 + */ + createTime?: Date; + /** + * 更新时间 + */ + updateTime?: Date; + /** + * 任意键值 + */ + [key: string]: any; + } + + interface AppGoodsEntity { + /** + * ID + */ + id?: number; + /** + * 标题 + */ + title?: string; + /** + * 价格 + */ + price?: number; + /** + * 原价 + */ + originalPrice?: number; + /** + * 描述 + */ + description?: string; + /** + * 状态 0-禁用 1-启用 + */ + status?: number; + /** + * 排序 + */ + sort?: number; + /** + * 类型 0-天 1-月 2-年 3-永久 + */ + type?: number; + /** + * 时长 + */ + duration?: number; + /** + * 标签 + */ + tag?: string; + /** + * 标签颜色 + */ + tagColor?: string; + /** + * 创建时间 + */ + createTime?: Date; + /** + * 更新时间 + */ + updateTime?: Date; + /** + * 任意键值 + */ + [key: string]: any; + } + + interface AppVersionEntity { + /** + * ID + */ + id?: number; + /** + * 名称 + */ + name?: string; + /** + * 版本号 + */ + version?: string; + /** + * 类型 + */ + type?: number; + /** + * 下载地址 + */ + url?: string; + /** + * 强制更新 0-否 1-是 + */ + forceUpdate?: number; + /** + * 状态 0-禁用 1-启用 + */ + status?: number; + /** + * 热更新 0-否 1-是 + */ + hotUpdate?: number; + /** + * 描述 + */ + description?: string; + /** + * 创建时间 + */ + createTime?: Date; + /** + * 更新时间 + */ + updateTime?: Date; + /** + * 任意键值 + */ + [key: string]: any; + } + + interface CsMsgEntity { + /** + * ID + */ + id?: number; + /** + * 用户ID + */ + userId?: number; + /** + * 会话ID + */ + sessionId?: number; + /** + * 消息内容 + */ + content?: json; + /** + * 类型 0-反馈 1-回复 + */ + type?: number; + /** + * 状态 0-未读 1-已读 + */ + status?: number; + /** + * 创建时间 + */ + createTime?: Date; + /** + * 更新时间 + */ + updateTime?: Date; + /** + * 任意键值 + */ + [key: string]: any; + } + + interface GoodsCommentEntity { + /** + * ID + */ + id?: number; + /** + * 用户ID + */ + userId?: number; + /** + * 商品ID + */ + goodsId?: number; + /** + * 订单ID + */ + orderId?: number; + /** + * 内容 + */ + content?: string; + /** + * 星数 + */ + starCount?: number; + /** + * 图片 + */ + pics?: json; + /** + * 创建时间 + */ + createTime?: Date; + /** + * 更新时间 + */ + updateTime?: Date; + /** + * 任意键值 + */ + [key: string]: any; + } + + interface GoodsInfoEntity { + /** + * ID + */ + id?: number; + /** + * 类型ID + */ + typeId?: number; + /** + * 标题 + */ + title?: string; + /** + * 副标题 + */ + subTitle?: string; + /** + * 主图 + */ + mainPic?: string; + /** + * 图片 + */ + pics?: json; + /** + * 价格 + */ + price?: number; + /** + * 已售 + */ + sold?: number; + /** + * 详情 + */ + content?: string; + /** + * 状态 0-下架 1-上架 + */ + status?: number; + /** + * 排序 + */ + sortNum?: number; + /** + * 创建时间 + */ + createTime?: Date; + /** + * 更新时间 + */ + updateTime?: Date; + /** + * 任意键值 + */ + [key: string]: any; + } + + interface GoodsSearchKeywordEntity { + /** + * ID + */ + id?: number; + /** + * 名称 + */ + name?: string; + /** + * 排序 + */ + sortNum?: number; + /** + * 创建时间 + */ + createTime?: Date; + /** + * 更新时间 + */ + updateTime?: Date; + /** + * 任意键值 + */ + [key: string]: any; + } + + interface GoodsSpecEntity { + /** + * ID + */ + id?: number; + /** + * 商品ID + */ + goodsId?: number; + /** + * 名称 + */ + name?: string; + /** + * 价格 + */ + price?: number; + /** + * 库存 + */ + stock?: number; + /** + * 排序 + */ + sortNum?: number; + /** + * 图片 + */ + images?: json; + /** + * 创建时间 + */ + createTime?: Date; + /** + * 更新时间 + */ + updateTime?: Date; + /** + * 任意键值 + */ + [key: string]: any; + } + + interface GoodsTypeEntity { + /** + * ID + */ + id?: number; + /** + * 名称 + */ + name?: string; + /** + * 父ID + */ + parentId?: number; + /** + * 排序 + */ + sortNum?: number; + /** + * 图片 + */ + pic?: string; + /** + * 状态 0-禁用 1-启用 + */ + status?: number; + /** + * 创建时间 + */ + createTime?: Date; + /** + * 更新时间 + */ + updateTime?: Date; + /** + * 任意键值 + */ + [key: string]: any; + } + + interface InfoBannerEntity { + /** + * ID + */ + id?: number; + /** + * 描述 + */ + description?: string; + /** + * 跳转路径 + */ + path?: string; + /** + * 图片 + */ + pic?: string; + /** + * 排序 + */ + sortNum?: number; + /** + * 状态 1:启用 2:禁用 + */ + status?: number; + /** + * 创建时间 + */ + createTime?: Date; + /** + * 更新时间 + */ + updateTime?: Date; + /** + * 任意键值 + */ + [key: string]: any; + } + + interface MarketCouponInfoEntity { + /** + * ID + */ + id?: number; + /** + * 标题 + */ + title?: string; + /** + * 描述 + */ + description?: string; + /** + * 类型 0-满减 + */ + type?: number; + /** + * 金额 + */ + amount?: number; + /** + * 数量 + */ + num?: number; + /** + * 已领取 + */ + receivedNum?: number; + /** + * 开始时间 + */ + startTime?: Date; + /** + * 结束时间 + */ + endTime?: Date; + /** + * 状态 0-禁用 1-启用 + */ + status?: number; + /** + * 条件 + */ + condition?: json; + /** + * 创建时间 + */ + createTime?: Date; + /** + * 更新时间 + */ + updateTime?: Date; + /** + * 任意键值 + */ + [key: string]: any; + } + + interface MarketCouponUserEntity { + /** + * ID + */ + id?: number; + /** + * 用户ID + */ + userId?: number; + /** + * 优惠券ID + */ + couponId?: number; + /** + * 状态 0-未使用 1-已使用 + */ + status?: number; + /** + * 使用时间 + */ + useTime?: Date; + /** + * 创建时间 + */ + createTime?: Date; + /** + * 更新时间 + */ + updateTime?: Date; + /** + * 任意键值 + */ + [key: string]: any; + } + + interface OrderInfoEntity { + /** + * ID + */ + id?: number; + /** + * 用户ID + */ + userId?: number; + /** + * 标题 + */ + title?: string; + /** + * 支付方式 0-待支付 1-微信 2-支付宝 + */ + payType?: number; + /** + * 支付时间 + */ + payTime?: Date; + /** + * 订单号 + */ + orderNum?: string; + /** + * 状态 0-待付款 1-待发货 2-待收货 3-待评价 4-交易完成 5-退款中 6-已退款 7-已关闭 + */ + status?: number; + /** + * 价格 + */ + price?: number; + /** + * 优惠金额 + */ + discountPrice?: number; + /** + * 优惠来源 + */ + discountSource?: json; + /** + * 地址 + */ + address?: json; + /** + * 物流信息 + */ + logistics?: json; + /** + * 退款 + */ + refund?: json; + /** + * 退款状态 + */ + refundStatus?: number; + /** + * 退款申请时间 + */ + refundApplyTime?: Date; + /** + * 备注 + */ + remark?: string; + /** + * 关闭备注 + */ + closeRemark?: string; + /** + * 已开票: 0-未开票 1-已开票 + */ + invoice?: number; + /** + * 微信类型 0-小程序 1-公众号 2-App + */ + wxType?: number; + /** + * 创建时间 + */ + createTime?: Date; + /** + * 更新时间 + */ + updateTime?: Date; + /** + * 任意键值 + */ + [key: string]: any; + } + + interface UserAddressEntity { + /** + * ID + */ + id?: number; + /** + * 用户ID + */ + userId?: number; + /** + * 联系人 + */ + contact?: string; + /** + * 手机号 + */ + phone?: string; + /** + * 省 + */ + province?: string; + /** + * 市 + */ + city?: string; + /** + * 区 + */ + district?: string; + /** + * 地址 + */ + address?: string; + /** + * 是否默认 + */ + isDefault?: boolean; + /** + * 创建时间 + */ + createTime?: Date; + /** + * 更新时间 + */ + updateTime?: Date; + /** + * 任意键值 + */ + [key: string]: any; + } + + interface UserInfoEntity { + /** + * ID + */ + id?: number; + /** + * 登录唯一ID + */ + unionid?: string; + /** + * 头像 + */ + avatarUrl?: string; + /** + * 昵称 + */ + nickName?: string; + /** + * 手机号 + */ + phone?: string; + /** + * 性别 0-未知 1-男 2-女 + */ + gender?: number; + /** + * 状态 0-禁用 1-正常 2-已注销 + */ + status?: number; + /** + * 登录方式 0-小程序 1-公众号 2-H5 + */ + loginType?: number; + /** + * 密码 + */ + password?: string; + /** + * 创建时间 + */ + createTime?: Date; + /** + * 更新时间 + */ + updateTime?: Date; + /** + * 任意键值 + */ + [key: string]: any; + } + + interface TestEntity { + /** + * 任意键值 + */ + [key: string]: any; + } + interface AppComplain { + /** + * 提交投诉举报 + */ + submit(data?: any): Promise; + /** + * 分页查询 + */ + page(data?: any): Promise<{ + pagination: { size: number; page: number; total: number; [key: string]: any }; + list: AppComplainEntity[]; + [key: string]: any; + }>; + /** + * 单个信息 + */ + info(data?: any): Promise; + /** + * 权限标识 + */ + permission: { submit: string; page: string; info: string }; + /** + * 权限状态 + */ + _permission: { submit: boolean; page: boolean; info: boolean }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface AppFeedback { + /** + * 提交意见反馈 + */ + submit(data?: any): Promise; + /** + * 分页查询 + */ + page(data?: any): Promise<{ + pagination: { size: number; page: number; total: number; [key: string]: any }; + list: AppFeedbackEntity[]; + [key: string]: any; + }>; + /** + * 单个信息 + */ + info(data?: any): Promise; + /** + * 权限标识 + */ + permission: { submit: string; page: string; info: string }; + /** + * 权限状态 + */ + _permission: { submit: boolean; page: boolean; info: boolean }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface AppGoods { + /** + * 列表查询 + */ + list(data?: any): Promise; + /** + * 权限标识 + */ + permission: { list: string }; + /** + * 权限状态 + */ + _permission: { list: boolean }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface AppVersion { + /** + * 检查版本 + */ + check(data?: any): Promise; + /** + * 权限标识 + */ + permission: { check: string }; + /** + * 权限状态 + */ + _permission: { check: boolean }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface BaseComm { + /** + * 文件上传模式 + */ + uploadMode(data?: any): Promise; + /** + * 文件上传 + */ + upload(data?: any): Promise; + /** + * 参数配置 + */ + param(data?: any): Promise; + /** + * 实体信息与路径 + */ + eps(data?: any): Promise; + /** + * 权限标识 + */ + permission: { uploadMode: string; upload: string; param: string; eps: string }; + /** + * 权限状态 + */ + _permission: { uploadMode: boolean; upload: boolean; param: boolean; eps: boolean }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface CsMsg { + /** + * 未读消息数 + */ + unreadCount(data?: any): Promise; + /** + * 标记已读 + */ + read(data?: any): Promise; + /** + * 分页查询 + */ + page(data?: any): Promise<{ + pagination: { size: number; page: number; total: number; [key: string]: any }; + list: CsMsgEntity[]; + [key: string]: any; + }>; + /** + * 权限标识 + */ + permission: { unreadCount: string; read: string; page: string }; + /** + * 权限状态 + */ + _permission: { unreadCount: boolean; read: boolean; page: boolean }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface CsSession { + /** + * 会话详情 + */ + detail(data?: any): Promise; + /** + * 创建会话 + */ + create(data?: any): Promise; + /** + * 权限标识 + */ + permission: { detail: string; create: string }; + /** + * 权限状态 + */ + _permission: { detail: boolean; create: boolean }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface DictInfo { + /** + * 获得字典数据 + */ + data(data?: any): Promise; + /** + * 权限标识 + */ + permission: { data: string }; + /** + * 权限状态 + */ + _permission: { data: boolean }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface GoodsComment { + /** + * 提交评论 + */ + submit(data?: any): Promise; + /** + * 分页查询 + */ + page(data?: any): Promise<{ + pagination: { size: number; page: number; total: number; [key: string]: any }; + list: GoodsCommentEntity[]; + [key: string]: any; + }>; + /** + * 权限标识 + */ + permission: { submit: string; page: string }; + /** + * 权限状态 + */ + _permission: { submit: boolean; page: boolean }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface GoodsInfo { + /** + * 分页查询 + */ + page(data?: any): Promise<{ + pagination: { size: number; page: number; total: number; [key: string]: any }; + list: GoodsInfoEntity[]; + [key: string]: any; + }>; + /** + * 单个信息 + */ + info(data?: any): Promise; + /** + * 权限标识 + */ + permission: { page: string; info: string }; + /** + * 权限状态 + */ + _permission: { page: boolean; info: boolean }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface GoodsSearchKeyword { + /** + * 删除 + */ + delete(data?: any): Promise; + /** + * 修改 + */ + update(data?: any): Promise; + /** + * 单个信息 + */ + info(data?: any): Promise; + /** + * 列表查询 + */ + list(data?: any): Promise; + /** + * 分页查询 + */ + page(data?: any): Promise<{ + pagination: { size: number; page: number; total: number; [key: string]: any }; + list: GoodsSearchKeywordEntity[]; + [key: string]: any; + }>; + /** + * 新增 + */ + add(data?: any): Promise; + /** + * 权限标识 + */ + permission: { + delete: string; + update: string; + info: string; + list: string; + page: string; + add: string; + }; + /** + * 权限状态 + */ + _permission: { + delete: boolean; + update: boolean; + info: boolean; + list: boolean; + page: boolean; + add: boolean; + }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface GoodsSpec { + /** + * 删除 + */ + delete(data?: any): Promise; + /** + * 修改 + */ + update(data?: any): Promise; + /** + * 单个信息 + */ + info(data?: any): Promise; + /** + * 列表查询 + */ + list(data?: any): Promise; + /** + * 分页查询 + */ + page(data?: any): Promise<{ + pagination: { size: number; page: number; total: number; [key: string]: any }; + list: GoodsSpecEntity[]; + [key: string]: any; + }>; + /** + * 新增 + */ + add(data?: any): Promise; + /** + * 权限标识 + */ + permission: { + delete: string; + update: string; + info: string; + list: string; + page: string; + add: string; + }; + /** + * 权限状态 + */ + _permission: { + delete: boolean; + update: boolean; + info: boolean; + list: boolean; + page: boolean; + add: boolean; + }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface GoodsType { + /** + * 列表查询 + */ + list(data?: any): Promise; + /** + * 权限标识 + */ + permission: { list: string }; + /** + * 权限状态 + */ + _permission: { list: boolean }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface InfoBanner { + /** + * 列表查询 + */ + list(data?: any): Promise; + /** + * 权限标识 + */ + permission: { list: string }; + /** + * 权限状态 + */ + _permission: { list: boolean }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface MarketCouponInfo { + /** + * 分页查询 + */ + page(data?: any): Promise<{ + pagination: { size: number; page: number; total: number; [key: string]: any }; + list: MarketCouponInfoEntity[]; + [key: string]: any; + }>; + /** + * 权限标识 + */ + permission: { page: string }; + /** + * 权限状态 + */ + _permission: { page: boolean }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface MarketCouponUser { + /** + * 领取优惠券 + */ + receive(data?: any): Promise; + /** + * 删除 + */ + delete(data?: any): Promise; + /** + * 修改 + */ + update(data?: any): Promise; + /** + * 单个信息 + */ + info(data?: any): Promise; + /** + * 列表查询 + */ + list(data?: any): Promise; + /** + * 分页查询 + */ + page(data?: any): Promise<{ + pagination: { size: number; page: number; total: number; [key: string]: any }; + list: MarketCouponUserEntity[]; + [key: string]: any; + }>; + /** + * 新增 + */ + add(data?: any): Promise; + /** + * 权限标识 + */ + permission: { + receive: string; + delete: string; + update: string; + info: string; + list: string; + page: string; + add: string; + }; + /** + * 权限状态 + */ + _permission: { + receive: boolean; + delete: boolean; + update: boolean; + info: boolean; + list: boolean; + page: boolean; + add: boolean; + }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface OrderInfo { + /** + * 物流信息 + */ + logistics(data?: any): Promise; + /** + * 用户订单统计 + */ + userCount(data?: any): Promise; + /** + * 确认收货 + */ + confirm(data?: any): Promise; + /** + * 创建订单 + */ + create(data?: any): Promise; + /** + * 取消订单 + */ + cancel(data?: any): Promise; + /** + * 退款 + */ + refund(data?: any): Promise; + /** + * 修改 + */ + update(data?: any): Promise; + /** + * 单个信息 + */ + info(data?: any): Promise; + /** + * 分页查询 + */ + page(data?: any): Promise<{ + pagination: { size: number; page: number; total: number; [key: string]: any }; + list: OrderInfoEntity[]; + [key: string]: any; + }>; + /** + * 权限标识 + */ + permission: { + logistics: string; + userCount: string; + confirm: string; + create: string; + cancel: string; + refund: string; + update: string; + info: string; + page: string; + }; + /** + * 权限状态 + */ + _permission: { + logistics: boolean; + userCount: boolean; + confirm: boolean; + create: boolean; + cancel: boolean; + refund: boolean; + update: boolean; + info: boolean; + page: boolean; + }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface OrderPay { + /** + * 微信小程序支付 + */ + wxMiniPay(data?: any): Promise; + /** + * 微信支付回调 + */ + wxNotify(data?: any): Promise; + /** + * 微信APP支付 + */ + wxAppPay(data?: any): Promise; + /** + * 微信公众号支付 + */ + wxMpPay(data?: any): Promise; + /** + * 权限标识 + */ + permission: { wxMiniPay: string; wxNotify: string; wxAppPay: string; wxMpPay: string }; + /** + * 权限状态 + */ + _permission: { wxMiniPay: boolean; wxNotify: boolean; wxAppPay: boolean; wxMpPay: boolean }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface UserAddress { + /** + * 默认地址 + */ + default(data?: any): Promise; + /** + * 删除 + */ + delete(data?: any): Promise; + /** + * 修改 + */ + update(data?: any): Promise; + /** + * 单个信息 + */ + info(data?: any): Promise; + /** + * 列表查询 + */ + list(data?: any): Promise; + /** + * 分页查询 + */ + page(data?: any): Promise<{ + pagination: { size: number; page: number; total: number; [key: string]: any }; + list: UserAddressEntity[]; + [key: string]: any; + }>; + /** + * 新增 + */ + add(data?: any): Promise; + /** + * 权限标识 + */ + permission: { + default: string; + delete: string; + update: string; + info: string; + list: string; + page: string; + add: string; + }; + /** + * 权限状态 + */ + _permission: { + default: boolean; + delete: boolean; + update: boolean; + info: boolean; + list: boolean; + page: boolean; + add: boolean; + }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface UserComm { + /** + * 获取微信公众号配置 + */ + wxMpConfig(data?: any): Promise; + /** + * 权限标识 + */ + permission: { wxMpConfig: string }; + /** + * 权限状态 + */ + _permission: { wxMpConfig: boolean }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface UserInfo { + /** + * 更新用户密码 + */ + updatePassword(data?: any): Promise; + /** + * 更新用户信息 + */ + updatePerson(data?: any): Promise; + /** + * 绑定手机号 + */ + bindPhone(data?: any): Promise; + /** + * 绑定小程序手机号 + */ + miniPhone(data?: any): Promise; + /** + * 获取用户信息 + */ + person(data?: any): Promise; + /** + * 注销 + */ + logoff(data?: any): Promise; + /** + * 权限标识 + */ + permission: { + updatePassword: string; + updatePerson: string; + bindPhone: string; + miniPhone: string; + person: string; + logoff: string; + }; + /** + * 权限状态 + */ + _permission: { + updatePassword: boolean; + updatePerson: boolean; + bindPhone: boolean; + miniPhone: boolean; + person: boolean; + logoff: boolean; + }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface UserLogin { + /** + * 刷新token + */ + refreshToken(data?: any): Promise; + /** + * 密码登录 + */ + password(data?: any): Promise; + /** + * 图片验证码 + */ + captcha(data?: any): Promise; + /** + * 验证码 + */ + smsCode(data?: any): Promise; + /** + * 微信APP授权登录 + */ + wxApp(data?: any): Promise; + /** + * 手机号登录 + */ + phone(data?: any): Promise; + /** + * 小程序登录 + */ + mini(data?: any): Promise; + /** + * 公众号登录 + */ + mp(data?: any): Promise; + /** + * 权限标识 + */ + permission: { + refreshToken: string; + password: string; + captcha: string; + smsCode: string; + wxApp: string; + phone: string; + mini: string; + mp: string; + }; + /** + * 权限状态 + */ + _permission: { + refreshToken: boolean; + password: boolean; + captcha: boolean; + smsCode: boolean; + wxApp: boolean; + phone: boolean; + mini: boolean; + mp: boolean; + }; + /** + * 请求 + */ + request: Service["request"]; + } + + interface Test { + /** + * page + */ + page(data?: any): Promise<{ + pagination: { size: number; page: number; total: number; [key: string]: any }; + list: TestEntity[]; + [key: string]: any; + }>; + /** + * list + */ + list(data?: any): Promise; + /** + * info + */ + info(data?: any): Promise; + /** + * delete + */ + delete(data?: any): Promise; + /** + * update + */ + update(data?: any): Promise; + /** + * add + */ + add(data?: any): Promise; + /** + * 权限标识 + */ + permission: { + page: string; + list: string; + info: string; + delete: string; + update: string; + add: string; + }; + /** + * 权限状态 + */ + _permission: { + page: boolean; + list: boolean; + info: boolean; + delete: boolean; + update: boolean; + add: boolean; + }; + /** + * 请求 + */ + request: Service["request"]; + } + + type json = any; + + type Service = { + request(options?: { + url: string; + method?: "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS"; + data?: any; + params?: any; + headers?: { + [key: string]: any; + }; + timeout?: number; + proxy?: boolean; + [key: string]: any; + }): Promise; + app: { complain: AppComplain; feedback: AppFeedback; goods: AppGoods; version: AppVersion }; + base: { comm: BaseComm }; + cs: { msg: CsMsg; session: CsSession }; + dict: { info: DictInfo }; + goods: { + comment: GoodsComment; + info: GoodsInfo; + searchKeyword: GoodsSearchKeyword; + spec: GoodsSpec; + type: GoodsType; + }; + info: { banner: InfoBanner }; + market: { coupon: { info: MarketCouponInfo; user: MarketCouponUser } }; + order: { info: OrderInfo; pay: OrderPay }; + user: { address: UserAddress; comm: UserComm; info: UserInfo; login: UserLogin }; + test: Test; + }; +} diff --git a/build/cool/eps.json b/build/cool/eps.json new file mode 100644 index 0000000..2069768 --- /dev/null +++ b/build/cool/eps.json @@ -0,0 +1 @@ +[{"prefix":"/app/app/complain","name":"AppComplainEntity","api":[{"method":"post","path":"/submit"},{"method":"post","path":"/page"},{"method":"get","path":"/info"}]},{"prefix":"/app/app/feedback","name":"AppFeedbackEntity","api":[{"method":"post","path":"/submit"},{"method":"post","path":"/page"},{"method":"get","path":"/info"}]},{"prefix":"/app/app/goods","name":"AppGoodsEntity","api":[{"method":"post","path":"/list"}]},{"prefix":"/app/app/version","name":"AppVersionEntity","api":[{"method":"get","path":"/check"}]},{"prefix":"/app/base/comm","name":"","api":[{"method":"get","path":"/uploadMode"},{"method":"post","path":"/upload"},{"method":"get","path":"/param"},{"method":"get","path":"/eps"}]},{"prefix":"/app/cs/msg","name":"CsMsgEntity","api":[{"method":"get","path":"/unreadCount"},{"method":"post","path":"/read"},{"method":"post","path":"/page"}]},{"prefix":"/app/cs/session","name":"","api":[{"method":"get","path":"/detail"},{"method":"post","path":"/create"}]},{"prefix":"/app/dict/info","name":"","api":[{"method":"post","path":"/data"}]},{"prefix":"/app/goods/comment","name":"GoodsCommentEntity","api":[{"method":"post","path":"/submit"},{"method":"post","path":"/page"}]},{"prefix":"/app/goods/info","name":"GoodsInfoEntity","api":[{"method":"post","path":"/page"},{"method":"get","path":"/info"}]},{"prefix":"/app/goods/searchKeyword","name":"GoodsSearchKeywordEntity","api":[{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"get","path":"/info"},{"method":"post","path":"/list"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}]},{"prefix":"/app/goods/spec","name":"GoodsSpecEntity","api":[{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"get","path":"/info"},{"method":"post","path":"/list"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}]},{"prefix":"/app/goods/type","name":"GoodsTypeEntity","api":[{"method":"post","path":"/list"}]},{"prefix":"/app/info/banner","name":"InfoBannerEntity","api":[{"method":"post","path":"/list"}]},{"prefix":"/app/market/coupon/info","name":"MarketCouponInfoEntity","api":[{"method":"post","path":"/page"}]},{"prefix":"/app/market/coupon/user","name":"MarketCouponUserEntity","api":[{"method":"post","path":"/receive"},{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"get","path":"/info"},{"method":"post","path":"/list"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}]},{"prefix":"/app/order/info","name":"OrderInfoEntity","api":[{"method":"get","path":"/logistics"},{"method":"get","path":"/userCount"},{"method":"get","path":"/confirm"},{"method":"post","path":"/create"},{"method":"post","path":"/cancel"},{"method":"post","path":"/refund"},{"method":"post","path":"/update"},{"method":"get","path":"/info"},{"method":"post","path":"/page"}]},{"prefix":"/app/order/pay","name":"","api":[{"method":"post","path":"/wxMiniPay"},{"method":"post","path":"/wxNotify"},{"method":"post","path":"/wxAppPay"},{"method":"post","path":"/wxMpPay"}]},{"prefix":"/app/user/address","name":"UserAddressEntity","api":[{"method":"get","path":"/default"},{"method":"post","path":"/delete"},{"method":"post","path":"/update"},{"method":"get","path":"/info"},{"method":"post","path":"/list"},{"method":"post","path":"/page"},{"method":"post","path":"/add"}]},{"prefix":"/app/user/comm","name":"","api":[{"method":"post","path":"/wxMpConfig"}]},{"prefix":"/app/user/info","name":"UserInfoEntity","api":[{"method":"post","path":"/updatePassword"},{"method":"post","path":"/updatePerson"},{"method":"post","path":"/bindPhone"},{"method":"post","path":"/miniPhone"},{"method":"get","path":"/person"},{"method":"post","path":"/logoff"}]},{"prefix":"/app/user/login","name":"","api":[{"method":"post","path":"/refreshToken"},{"method":"post","path":"/password"},{"method":"get","path":"/captcha"},{"method":"post","path":"/smsCode"},{"method":"post","path":"/wxApp"},{"method":"post","path":"/phone"},{"method":"post","path":"/mini"},{"method":"post","path":"/mp"}]},{"prefix":"/","name":"","api":[{"method":"get","path":"/"}]},{"prefix":"/app/test","name":"TestEntity","api":[{"path":"/page"},{"path":"/list"},{"path":"/info"},{"path":"/delete"},{"path":"/update"},{"path":"/add"}]}] \ No newline at end of file diff --git a/components/address/item.vue b/components/address/item.vue new file mode 100644 index 0000000..31c6fe2 --- /dev/null +++ b/components/address/item.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/components/address/select.vue b/components/address/select.vue new file mode 100644 index 0000000..20307c5 --- /dev/null +++ b/components/address/select.vue @@ -0,0 +1,150 @@ + + + + + diff --git a/components/agree-btn.vue b/components/agree-btn.vue new file mode 100644 index 0000000..80dd6ad --- /dev/null +++ b/components/agree-btn.vue @@ -0,0 +1,58 @@ + + + + + diff --git a/components/coupon/get.vue b/components/coupon/get.vue new file mode 100644 index 0000000..4f52545 --- /dev/null +++ b/components/coupon/get.vue @@ -0,0 +1,166 @@ + + + + + diff --git a/components/coupon/item/bg.png b/components/coupon/item/bg.png new file mode 100644 index 0000000..d15f48a Binary files /dev/null and b/components/coupon/item/bg.png differ diff --git a/components/coupon/item/index.vue b/components/coupon/item/index.vue new file mode 100644 index 0000000..3095936 --- /dev/null +++ b/components/coupon/item/index.vue @@ -0,0 +1,168 @@ + + + + + diff --git a/components/coupon/select.vue b/components/coupon/select.vue new file mode 100644 index 0000000..a4add51 --- /dev/null +++ b/components/coupon/select.vue @@ -0,0 +1,134 @@ + + + + + diff --git a/components/goods/cover.vue b/components/goods/cover.vue new file mode 100644 index 0000000..f6a1c49 --- /dev/null +++ b/components/goods/cover.vue @@ -0,0 +1,96 @@ + + + + + diff --git a/components/goods/group.vue b/components/goods/group.vue new file mode 100644 index 0000000..f931058 --- /dev/null +++ b/components/goods/group.vue @@ -0,0 +1,202 @@ + + + + + diff --git a/components/goods/item.vue b/components/goods/item.vue new file mode 100644 index 0000000..4c25343 --- /dev/null +++ b/components/goods/item.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/components/goods/spec.vue b/components/goods/spec.vue new file mode 100644 index 0000000..a5b4d5e --- /dev/null +++ b/components/goods/spec.vue @@ -0,0 +1,393 @@ + + + + + diff --git a/components/sms-btn.vue b/components/sms-btn.vue new file mode 100644 index 0000000..87b64d0 --- /dev/null +++ b/components/sms-btn.vue @@ -0,0 +1,229 @@ + + + + + diff --git a/config/dev.ts b/config/dev.ts new file mode 100644 index 0000000..7d7ea94 --- /dev/null +++ b/config/dev.ts @@ -0,0 +1,17 @@ +import { proxy } from "./proxy"; + +export default { + // 根地址 + host: proxy["/dev/"].target, + + // 请求地址 + get baseUrl() { + // #ifdef H5 + return "/dev"; + // #endif + + // #ifndef H5 + return this.host + ""; + // #endif + }, +}; diff --git a/config/index.ts b/config/index.ts new file mode 100644 index 0000000..41652ef --- /dev/null +++ b/config/index.ts @@ -0,0 +1,40 @@ +import dev from "./dev"; +import prod from "./prod"; + +// 是否开发模式 +export const isDev = import.meta.env.MODE === "development"; + +// 配置 +export const config = { + // 应用信息 + app: { + // 应用名称 + name: "酷卖", + // 应用描述 + desc: "能用钱解决的事,就不要客气", + // 页面配置 + pages: { + login: "/pages/user/login", + }, + wx: { + debug: false, + }, + }, + + // 调试 + test: { + token: "", + mock: false, + eps: true, + }, + + // 忽略 + ignore: { + token: [], + }, + + // 当前环境 + ...(isDev ? dev : prod), +}; + +export * from "./proxy"; diff --git a/config/prod.ts b/config/prod.ts new file mode 100644 index 0000000..138645d --- /dev/null +++ b/config/prod.ts @@ -0,0 +1,18 @@ +import { proxy } from "./proxy"; + +export default { + // 根地址 + host: proxy["/prod/"].target, + + // 请求地址 + get baseUrl() { + // #ifdef H5 + return "/api"; + // #endif + + // #ifndef H5 + return "https://cool-mall-dev.cool-js.cloud"; + // return this.host + "/api"; + // #endif + }, +}; diff --git a/config/proxy.ts b/config/proxy.ts new file mode 100644 index 0000000..1305315 --- /dev/null +++ b/config/proxy.ts @@ -0,0 +1,13 @@ +export const proxy = { + "/dev/": { + target: "http://127.0.0.1:8001", + changeOrigin: true, + rewrite: (path: string) => path.replace(/^\/dev/, ""), + }, + + "/prod/": { + target: "https://cool-mall-dev.cool-js.cloud", + changeOrigin: true, + rewrite: (path: string) => path.replace(/^\/prod/, ""), + }, +}; diff --git a/cool/bootstrap/eps.ts b/cool/bootstrap/eps.ts new file mode 100644 index 0000000..9a4f57b --- /dev/null +++ b/cool/bootstrap/eps.ts @@ -0,0 +1,138 @@ +import { merge } from "lodash-es"; +import { BaseService, service } from "../service"; +import { path2Obj } from "../utils"; +import { config, isDev } from "/@/config"; +import { eps } from "virtual:eps"; + +// 读取本地所有 service +const files = import.meta.glob("/service/**/*", { + eager: true, +}); + +// 数据集合 +const services: any[] = []; + +// 取值 +for (const i in files) { + try { + // @ts-ignore + services.push(new files[i].default()); + } catch (e) { + console.error(`[service] ${i} error: `, e); + } +} + +// 更新事件 +function onUpdate() { + // 设置 request 方法 + function set(d: any) { + if (d.namespace) { + const a: any = new BaseService(d.namespace); + + for (const i in d) { + const { path, method = "get" } = d[i]; + + if (path) { + a.request = a.request; + + a[i] = function (data?: any) { + return this.request({ + url: path, + method, + [method.toLocaleLowerCase() == "post" ? "data" : "params"]: data, + }); + }; + } + } + + for (const i in a) { + d[i] = a[i]; + } + } else { + for (const i in d) { + set(d[i]); + } + } + } + + // 遍历每一个方法 + set(eps.service); + + // 合并 eps + merge(service, eps.service); + + // 合并[local] + merge( + service, + path2Obj( + services.map((e) => { + return { + path: (e.namespace || "").replace("app/", ""), + value: e, + }; + }), + ), + ); + + // 提示 + if (isDev) { + console.log("[cool-eps] updated"); + } +} + +export function createEps() { + // 更新 eps + onUpdate(); + + // #ifdef H5 + // 开发环境下,生成本地 service 的类型描述文件 + if (isDev && config.test.eps) { + const list = services.map((s) => { + const api = Array.from( + new Set([ + ...Object.getOwnPropertyNames(s.constructor.prototype), + "page", + "list", + "info", + "delete", + "update", + "add", + ]), + ) + .filter((e) => !["constructor", "namespace"].includes(e)) + .map((e) => { + return { + path: `/${e}`, + }; + }); + + return { + api, + module: s.namespace.split("/")[0], + name: s.constructor.name + "Entity", + prefix: `/app/${s.namespace}`, + }; + }); + + service.request({ + url: "/__cool_eps", + method: "POST", + proxy: false, + data: { + list, + }, + }); + } + // #endif +} + +// 监听 vite 触发事件 +if (import.meta.hot) { + import.meta.hot.on("eps-update", ({ service }) => { + if (service) { + eps.service = service; + } + + onUpdate(); + }); +} diff --git a/cool/bootstrap/index.ts b/cool/bootstrap/index.ts new file mode 100644 index 0000000..eda703e --- /dev/null +++ b/cool/bootstrap/index.ts @@ -0,0 +1,15 @@ +import { createPinia } from "pinia"; +import { createEps } from "./eps"; +import { createModules } from "./modules"; +import { type App } from "vue"; + +export async function bootstrap(app: App) { + // 状态共享存储 + app.use(createPinia()); + + // 创建 EPS + createEps(); + + // 创建 uni_modules + createModules(); +} diff --git a/cool/bootstrap/modules.ts b/cool/bootstrap/modules.ts new file mode 100644 index 0000000..7a48445 --- /dev/null +++ b/cool/bootstrap/modules.ts @@ -0,0 +1,38 @@ +import { keys, orderBy } from "lodash-es"; +import { module } from "../module"; + +export async function createModules() { + // 加载 uni_modules 插件 + const files: any = import.meta.glob("/uni_modules/cool-*/config.ts", { + eager: true, + }); + + const modules = orderBy( + keys(files).map((k) => { + const [, , name] = k.split("/"); + + return { + name, + value: files[k]?.default, + }; + }), + "order", + "desc", + ); + + for (let i in modules) { + const { name, value } = modules[i]; + const data = value ? value() : undefined; + + // 添加模块 + module.add({ + name, + ...data, + }); + + // 触发加载事件 + if (data) { + await data.onLoad?.(data.options); + } + } +} diff --git a/cool/hooks/app.ts b/cool/hooks/app.ts new file mode 100644 index 0000000..317f494 --- /dev/null +++ b/cool/hooks/app.ts @@ -0,0 +1,28 @@ +import { reactive, ref } from "vue"; +import { storage } from "../utils"; +import { config } from "/@/config"; +import { defineStore } from "pinia"; + +// 主题 +export const useTheme = defineStore("theme", () => { + const name = ref(storage.get("theme") || "default"); + + function set(value: string) { + name.value = value; + storage.set("theme", value); + } + + return { + name, + set, + }; +}); + +export function useApp() { + const info = reactive(config.app); + + return { + info, + theme: useTheme(), + }; +} diff --git a/cool/hooks/comm.ts b/cool/hooks/comm.ts new file mode 100644 index 0000000..520ca45 --- /dev/null +++ b/cool/hooks/comm.ts @@ -0,0 +1,11 @@ +import { reactive } from "vue"; +export function useRefs() { + const refs = reactive<{ [key: string]: any }>({}); + function setRefs(name: string) { + return (el: any) => { + refs[name] = el; + }; + } + + return { refs, setRefs }; +} diff --git a/cool/hooks/hmr.ts b/cool/hooks/hmr.ts new file mode 100644 index 0000000..e7526ae --- /dev/null +++ b/cool/hooks/hmr.ts @@ -0,0 +1,23 @@ +// 解决热更新后失效问题; +const data = import.meta.hot?.data.getData?.() || {}; + +if (import.meta.hot) { + import.meta.hot.data.getData = () => { + return data; + }; +} + +export const hmr = { + data, + + setData(key: string, value: any) { + data[key] = value; + }, + + getData(key: string, defaultValue?: any) { + if (defaultValue !== undefined && !data[key]) { + this.setData(key, defaultValue); + } + return data[key]; + } +}; diff --git a/cool/hooks/index.ts b/cool/hooks/index.ts new file mode 100644 index 0000000..5ce6407 --- /dev/null +++ b/cool/hooks/index.ts @@ -0,0 +1,21 @@ +import { router } from "../router"; +import { service } from "../service"; +import { upload } from "../upload"; +import { storage } from "../utils"; +import { useRefs } from "./comm"; + +export function useCool() { + return { + router, + service, + upload, + storage, + ...useRefs(), + }; +} + +export * from "./app"; +export * from "./comm"; +export * from "./hmr"; +export * from "./pager"; +export * from "./wx"; diff --git a/cool/hooks/pager.ts b/cool/hooks/pager.ts new file mode 100644 index 0000000..b8993fa --- /dev/null +++ b/cool/hooks/pager.ts @@ -0,0 +1,168 @@ +import { computed, getCurrentInstance, onUnmounted, reactive } from "vue"; +import { onPullDownRefresh, onReachBottom, onUnload } from "@dcloudio/uni-app"; +import { useUi } from "/$/cool-ui"; + +interface Res { + list: any[]; + pagination: { + total: number; + page: number; + size: number; + [key: string]: any; + }; + [key: string]: any; +} + +export function usePager() { + const { proxy }: any = getCurrentInstance(); + const ui = useUi(); + + // 分页信息 + const pager = reactive({ + params: {}, + pagination: { + page: 1, + size: 20, + total: 0, + }, + list: [] as T[], + loading: false, + finished: false, + }); + + // 事件 + const events: any = {}; + + // 列表 + const list = computed(() => pager.list); + + // 刷新 + async function refresh(params?: any) { + if (pager.loading) { + return false; + } + + if (proxy.refresh) { + await proxy.refresh(params); + } else if (proxy.$.exposed.refresh) { + await proxy.$.exposed.refresh(params); + } else { + console.log("use defineExpose({ refresh })"); + } + } + + // 数据 + function onData(cb: (list: T[]) => void) { + events.onData = cb; + } + + // 刷新 + function onRefresh(params: any = {}, options?: { clear?: boolean; loading?: boolean }) { + const { clear, loading = true } = options || {}; + + // 是否清空 + if (clear) { + if (params.page == 1) { + pager.list = []; + pager.finished = false; + } + } + + // 合并请求参数 + Object.assign(pager.params, params); + + const data = { + ...pager.pagination, + ...pager.params, + total: undefined, + }; + + // 是否显示加载动画 + if (data.page == 1 && loading) { + ui.showLoading(); + } + + pager.loading = true; + + // 完成 + function done() { + ui.hideLoading(); + pager.loading = false; + } + + return { + data, + done, + next: (req: Promise) => { + return new Promise((resolve, reject) => { + req.then((res: Res) => { + // 设置列表数据 + if (data.page == 1) { + pager.list = res.list; + } else { + pager.list.push(...res.list); + } + + // 追加事件 + if (events.onData) { + events.onData(res.list); + } + + // 是否加载完成 + pager.finished = pager.list.length === res.pagination.total; + // 分页信息 + pager.pagination = res.pagination; + + done(); + resolve(res); + }).catch((err) => { + done(); + ui.showToast(err.message); + reject(err); + }); + }); + }, + }; + } + + // 关闭 + function close() { + isReg = false; + ui.hideLoading(); + } + + // 是否注册,避免在组件中重复注入事件问题 + let isReg = true; + + // 上拉加载 + onReachBottom(() => { + if (isReg) { + if (!pager.finished) { + refresh({ page: pager.pagination.page + 1 }); + } + } + }); + + // 下拉刷新 + onPullDownRefresh(async () => { + if (isReg) { + await refresh({ page: 1 }); + uni.stopPullDownRefresh(); + } + }); + + // 组件销毁 + onUnmounted(close); + + // 离开页面 + onUnload(close); + + return { + pager, + list, + onData, + onRefresh, + onPullDownRefresh, + onReachBottom, + }; +} diff --git a/cool/hooks/wx.ts b/cool/hooks/wx.ts new file mode 100644 index 0000000..7ac051e --- /dev/null +++ b/cool/hooks/wx.ts @@ -0,0 +1,288 @@ +import { ref } from "vue"; +import { onReady, onShow } from "@dcloudio/uni-app"; +import { config } from "/@/config"; +import { getUrlParam, storage } from "../utils"; +import { service } from "../service"; + +// #ifdef H5 +import wx from "weixin-js-sdk"; +// #endif + +export function useWx() { + const { platform } = uni.getSystemInfoSync(); + + // 授权码 + const code = ref(""); + + // 获取授权码 + async function getCode() { + return new Promise((resolve) => { + // #ifdef MP-WEIXIN + uni.login({ + provider: "weixin", + success: (res) => { + code.value = res.code; + resolve(res.code); + }, + }); + // #endif + }); + } + + // 是否微信浏览器 + function isWxBrowser() { + // #ifdef H5 + const ua: any = window.navigator.userAgent.toLowerCase(); + if (ua.match(/MicroMessenger/i) == "micromessenger") { + return true; + } else { + return false; + } + // #endif + + // #ifndef H5 + return false; + // #endif + } + + // 是否安装了微信 + function hasApp() { + // #ifdef APP + return plus.runtime.isApplicationExist({ pname: "com.tencent.mm", action: "weixin://" }); + // #endif + + // #ifndef APP + return true; + // #endif + } + + // 下载微信 + function downloadApp() { + // #ifdef APP + if (platform == "android") { + const Uri: any = plus.android.importClass("android.net.Uri"); + const uri: any = Uri.parse("market://details?id=" + "com.tencent.mm"); + const Intent: any = plus.android.importClass("android.content.Intent"); + const intent: any = new Intent(Intent.ACTION_VIEW, uri); + const main: any = plus.android.runtimeMainActivity(); + main.startActivity(intent); + } else { + plus.runtime.openURL( + "itms-apps://" + "itunes.apple.com/cn/app/wechat/id414478124?mt=8", + ); + } + // #endif + } + + // 微信公众号配置 + const mpConfig = { + appId: "", + }; + + // 获取微信公众号配置 + function getMpConfig() { + // #ifdef H5 + if (isWxBrowser()) { + service.user.comm + .wxMpConfig({ + url: `${location.origin}${location.pathname}`, + }) + .then((res) => { + wx.config({ + debug: config.app.wx.debug, + jsApiList: ["chooseWXPay"], + ...res, + }); + + Object.assign(mpConfig, res); + }); + } + // #endif + } + + // 微信公众号授权 + function mpAuth() { + const redirect_uri = encodeURIComponent( + `${location.origin}${location.pathname}#/pages/user/login`, + ); + const response_type = "code"; + const scope = "snsapi_userinfo"; + const state = "STATE"; + + const url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${mpConfig.appId}&redirect_uri=${redirect_uri}&response_type=${response_type}&scope=${scope}&state=${state}#wechat_redirect`; + + location.href = url; + } + + // 微信公众号登录 + async function mpLogin() { + return new Promise((resolve) => { + const code = getUrlParam("code"); + const mpCode = storage.get("mpCode"); + + let url = window.location.href; + url = url.replace(/(\?[^#]*)#/, "#"); + window.history.replaceState({}, "", url); + + if (code != mpCode) { + storage.set("mpCode", code); + resolve(code); + } else { + resolve(null); + } + }); + } + + // 微信公众号支付 + async function mpPay(params: wx.IchooseWXPay & { timeStamp: number }): Promise { + return new Promise((resolve, reject) => { + if (!isWxBrowser()) { + return reject({ + message: "请在微信浏览器中打开", + }); + } + + wx.chooseWXPay({ + ...params, + timestamp: params.timeStamp, + success() { + resolve(); + }, + complete(e: { errMsg: string }) { + switch (e.errMsg) { + case "chooseWXPay:cancel": + reject({ message: "已取消支付" }); + break; + + default: + reject({ message: "支付失败" }); + } + }, + }); + }); + } + + // 微信app登录 + function appLogin(): Promise { + let all: any; + let Service: any; + return new Promise((resolve, reject) => { + plus.oauth.getServices((Services: any) => { + all = Services; + Object.keys(all).some((key) => { + if (all[key].id == "weixin") { + Service = all[key]; + } + }); + Service.authorize(resolve, reject); + }, reject); + }); + } + + // 微信app支付 + function appPay(orderInfo: { + appid: string; + noncestr: string; + package: string; + partnerid: string; + prepayid: string; + timestamp: string; + sign: string; + [key: string]: any; + }): Promise { + return new Promise((resolve, reject) => { + uni.requestPayment({ + provider: "wxpay", + orderInfo, + success() { + resolve(); + }, + fail() { + reject({ message: "已取消支付" }); + }, + }); + }); + } + + // 微信小程序登录 + async function miniLogin(): Promise<{ code: string; [key: string]: any }> { + return new Promise((resolve, reject) => { + // 兼容 Mac + const k = platform === "mac" ? "getUserInfo" : "getUserProfile"; + + uni[k]({ + lang: "zh_CN", + desc: "授权信息仅用于用户登录", + success({ iv, encryptedData, signature, rawData }) { + function next() { + resolve({ + iv, + encryptedData, + signature, + rawData, + code: code.value, + }); + } + + // 检查登录状态是否过期 + uni.checkSession({ + success() { + next(); + }, + fail() { + getCode().then(next); + }, + }); + }, + fail(err) { + console.error(err); + getCode(); + + reject({ + message: "登录授权失败", + }); + }, + }); + }); + } + + // 微信小程序支付 + function miniPay(params: any): Promise { + return new Promise((resolve, reject) => { + uni.requestPayment({ + provider: "wxpay", + ...params, + success() { + resolve(); + }, + fail() { + reject({ message: "已取消支付" }); + }, + }); + }); + } + + onShow(() => { + getCode(); + }); + + onReady(() => { + getMpConfig(); + }); + + return { + code, + getCode, + isWxBrowser, + hasApp, + downloadApp, + mpConfig, + mpAuth, + mpLogin, + mpPay, + miniLogin, + miniPay, + appLogin, + appPay, + }; +} diff --git a/cool/index.ts b/cool/index.ts new file mode 100644 index 0000000..550ef18 --- /dev/null +++ b/cool/index.ts @@ -0,0 +1,9 @@ +export * from "./hooks"; +export * from "./router"; +export * from "./store"; +export * from "./upload"; +export * from "./service"; +export * from "./module"; +export * from "../config"; +export type * from "./types"; +export { storage } from "./utils"; diff --git a/cool/module/index.ts b/cool/module/index.ts new file mode 100644 index 0000000..c24aa68 --- /dev/null +++ b/cool/module/index.ts @@ -0,0 +1,21 @@ +import type { Module } from "../types"; +import { hmr } from "../hooks"; + +// 模块列表 +const list: Module[] = hmr.getData("modules", []); + +// 模块对象 +const module = { + list, + get(name: string): Module { + return this.list.find((e) => e.name == name)!; + }, + config(name: string) { + return this.get(name).options || {}; + }, + add(data: Module) { + this.list.push(data); + }, +}; + +export { module }; diff --git a/cool/router/index.ts b/cool/router/index.ts new file mode 100644 index 0000000..2bca00c --- /dev/null +++ b/cool/router/index.ts @@ -0,0 +1,325 @@ +import { last } from "lodash-es"; +import { ctx } from "virtual:ctx"; +import { storage } from "../utils"; +import { config } from "../../config"; + +type PushOptions = + | string + | { + path: string; + mode?: "navigateTo" | "redirectTo" | "reLaunch" | "switchTab" | "preloadPage"; + events?: { + [key: string]: (data: any) => void; + }; + query?: { + [key: string]: any; + }; + params?: { + [key: string]: any; + }; + isGuard?: boolean; + [key: string]: any; + }; + +type Tabs = { + text?: string; + pagePath: string; + iconPath?: string; + selectedIconPath?: string; + [key: string]: any; +}[]; + +// 路由列表 +const routes = [...ctx.pages]; + +// 子包 +if (ctx.subPackages) { + ctx.subPackages.forEach((a: { pages: any[]; root: string }) => { + a.pages.forEach((b) => { + routes.push({ + ...b, + path: a.root + "/" + b.path, + }); + }); + }); +} + +// 钩子函数 +const fn: { [key: string]: (...args: any[]) => any } = {}; + +// 路由 +const router = { + // 底部导航 + get tabs(): Tabs { + if (ctx.tabBar) { + return ctx.tabBar.list || []; + } else { + return []; + } + }, + + // 全局样式配置 + globalStyle: ctx.globalStyle, + + // 路由列表 + routes, + + // 地址栏参数 + get query() { + const info = this.info(); + + return { + ...info?.query, + }; + }, + + // 临时参数 + get params() { + return storage.get("router-params") || {}; + }, + + // 页面地址 + get pages() { + return { + home: "/" + (ctx.tabBar ? this.tabs[0].pagePath : ctx.pages[0].path), + ...config.app.pages, + }; + }, + + // 当前页 + currentPage(): { [key: string]: any } { + return last(getCurrentPages())!; + }, + + // 当前页 + get path() { + return router.info()?.path; + }, + + // 当前路由信息 + info() { + const page = last(getCurrentPages()); + + if (page) { + const { route, $page, $vm, $getAppWebview }: any = page; + + const q: any = {}; + + try { + $page?.fullPath + .split("?")[1] + .split("&") + .forEach((e: string) => { + const [k, v] = e.split("="); + q[k] = decodeURIComponent(v); + }); + } catch (e) {} + + // 页面配置 + const style = this.routes.find((e) => e.path == route)?.style; + + let d = { + $vm, + $getAppWebview, + path: `/${route}`, + fullPath: $page?.fullPath, + query: q || {}, + isTab: this.isTab(route), + style, + isCustomNavbar: style?.navigationStyle == "custom", + }; + + return d; + } else { + return null; + } + }, + + // 跳转 + push(options: PushOptions) { + if (typeof options == "string") { + options = { + path: options, + mode: "navigateTo", + }; + } + + let { + path, + mode = "navigateTo", + animationType, + animationDuration, + events, + success, + fail, + complete, + query, + params, + isGuard = true, + } = options || {}; + + if (query) { + let arr = []; + + for (let i in query) { + if (query[i] !== undefined) { + arr.push(`${i}=${query[i]}`); + } + } + + path += "?" + arr.join("&"); + } + + if (params) { + storage.set("router-params", params); + } + + let data = { + url: path, + animationType, + animationDuration, + events, + success, + fail, + complete, + }; + + if (this.isTab(path)) { + mode = "switchTab"; + } + + const next = () => { + switch (mode) { + case "navigateTo": + uni.navigateTo(data); + break; + + case "redirectTo": + uni.redirectTo(data); + break; + + case "reLaunch": + uni.reLaunch(data); + break; + + case "switchTab": + uni.switchTab(data); + break; + + case "preloadPage": + uni.preloadPage(data); + break; + } + }; + + if (fn.beforeEach && isGuard) { + fn.beforeEach({ path: options.path, query }, next, (options: PushOptions) => { + this.push(options); + }); + } else { + next(); + } + }, + + // 后退 + back(options?: UniApp.NavigateBackOptions) { + if (this.isFirstPage()) { + this.home(); + } else { + uni.navigateBack(options || {}); + } + }, + + // 执行当前页面的某个方法 + callMethod(name: string, data?: any) { + const { $vm } = this.info()!; + + if ($vm) { + if ($vm.$.exposed?.[name]) { + return $vm.$.exposed[name](data); + } + } + }, + + // 页面栈长度是否只有1 + isFirstPage() { + return getCurrentPages().length == 1; + }, + + // 是否当前页 + isCurrentPage(path: string) { + return this.info()?.path == path; + }, + + // 回到首页 + home() { + this.push(this.pages.home); + }, + + // tabbar + switchTab(name: string) { + let item = this.tabs.find((e) => e.pagePath.includes(name)); + + if (item) { + this.push({ + path: `/${item.pagePath}`, + mode: "switchTab", + }); + } else { + console.error("不存在Tab页", name); + } + }, + + // 是否是Tab页 + isTab(path: string) { + return !!this.tabs.find((e) => path == `/${e.pagePath}`); + }, + + // 去登陆 + login(options?: { reLaunch: boolean }) { + const { reLaunch = false } = options || {}; + + this.push({ + path: this.pages.login, + mode: reLaunch ? "reLaunch" : "navigateTo", + isGuard: false, + }); + }, + + // 登录成功后操作 + nextLogin(type?: string) { + const pages = getCurrentPages(); + const index = pages.findIndex((e) => this.pages.login.includes(e.route!)); + + if (index <= 0) { + this.home(); + } else { + router.back({ + delta: pages.length - index, + }); + } + + // 登录方式 + storage.set("loginType", type); + + // 登录回调 + if (fn.afterLogin) { + fn.afterLogin(); + } + + // 事件 + uni.$emit("afterLogin", { type }); + }, + + // 跳转前钩子 + beforeEach(callback: (to: any, next: () => void) => void) { + fn.beforeEach = callback; + }, + + // 登录后回调 + afterLogin(callback: () => void) { + fn.afterLogin = callback; + }, +}; + +export { router }; diff --git a/cool/service/base.ts b/cool/service/base.ts new file mode 100644 index 0000000..3411af4 --- /dev/null +++ b/cool/service/base.ts @@ -0,0 +1,123 @@ +// @ts-nocheck +import { has } from "lodash-es"; +import { isDev, config } from "../../config"; +import request from "./request"; + +export function Service( + value: + | { + namespace?: string; + url?: string; + mock?: boolean; + } + | string +) { + return function (target: any) { + // 命名 + if (typeof value == "string") { + target.prototype.namespace = value; + } + + // 复杂项 + if (has(value, "namespace")) { + target.prototype.namespace = value.namespace; + target.prototype.mock = value.mock; + + if (value.url) { + target.prototype.url = value.url; + } + } + }; +} + +export class BaseService { + constructor( + options = {} as { + namespace?: string; + } + ) { + if (options?.namespace) { + this.namespace = options.namespace; + } + } + + request(options: any = {}) { + if (!options.params) options.params = {}; + + let ns = ""; + + // 是否 mock 模式 + if (this.mock || config.test.mock) { + // 测试 + } else { + if (isDev) { + ns = this.proxy || config.baseUrl; + } else { + ns = this.proxy ? this.url : config.baseUrl; + } + } + + // 拼接前缀 + if (this.namespace) { + ns += "/" + this.namespace; + } + + // 处理地址 + if (options.proxy === undefined || options.proxy) { + options.url = ns + options.url; + } + + // 处理参数 + options.data = + options.method?.toLocaleUpperCase() == "POST" ? options.data : options.params; + + return request(options); + } + + list(data: any) { + return this.request({ + url: "/list", + method: "POST", + data, + }); + } + + page(data: any) { + return this.request({ + url: "/page", + method: "POST", + data, + }); + } + + info(params: any) { + return this.request({ + url: "/info", + params, + }); + } + + update(data: any) { + return this.request({ + url: "/update", + method: "POST", + data, + }); + } + + delete(data: any) { + return this.request({ + url: "/delete", + method: "POST", + data, + }); + } + + add(data: any) { + return this.request({ + url: "/add", + method: "POST", + data, + }); + } +} diff --git a/cool/service/index.ts b/cool/service/index.ts new file mode 100644 index 0000000..8b6c684 --- /dev/null +++ b/cool/service/index.ts @@ -0,0 +1,9 @@ +import { BaseService } from "./base"; + +// service 数据集合 +// @ts-ignore +export const service: Eps.Service = { + request: new BaseService().request, +}; + +export * from "./base"; diff --git a/cool/service/request.ts b/cool/service/request.ts new file mode 100644 index 0000000..ce69a75 --- /dev/null +++ b/cool/service/request.ts @@ -0,0 +1,132 @@ +import { useStore } from "../store"; +import { router } from "../router"; +import { isDev, config } from "../../config"; +import { storage } from "../utils"; + +// 请求队列 +let requests: any[] = []; + +// Token 是否刷新中 +let isRefreshing = false; + +export default function request(options: any) { + // 缓存信息 + const { user } = useStore(); + + // 标识 + let Authorization = user.token || ""; + + // 忽略标识 + config.ignore.token.forEach((e) => { + if (options.url.includes(e)) { + Authorization = ""; + } + }); + + if (isDev) { + console.log(`[${options.method || "GET"}] ${options.url}`); + } + + return new Promise(async (resolve, reject) => { + // 继续请求 + function next() { + uni.request({ + ...options, + + header: { + Authorization, + ...options.header, + }, + + success(res) { + const { code, data, message } = res.data as { + code: number; + message: string; + data: any; + }; + + // 无权限 + if (res.statusCode === 401) { + if (router.info()?.path == router.pages.login) { + return reject({ message }); + } else { + user.logout(); + } + } + + // 服务异常 + if (res.statusCode === 502) { + return reject({ + message: "服务异常", + }); + } + + // 未找到 + if (res.statusCode === 404) { + return reject({ + message: `[404] ${options.url}`, + }); + } + + // 成功 + if (res.statusCode === 200) { + switch (code) { + case 1000: + resolve(data); + break; + default: + reject({ message, code }); + } + } else { + reject({ message: "服务异常" }); + } + }, + + fail(err) { + reject({ message: err.errMsg }); + }, + }); + } + + // 刷新token处理 + if (!options.url.includes("refreshToken")) { + if (Authorization) { + // 判断 token 是否过期 + if (storage.isExpired("token")) { + // 判断 refreshToken 是否过期 + if (storage.isExpired("refreshToken")) { + // 退出登录 + return user.logout(); + } + + // 是否在刷新中 + if (!isRefreshing) { + isRefreshing = true; + user.refreshToken() + .then((token) => { + requests.forEach((cb) => cb(token)); + requests = []; + isRefreshing = false; + }) + .catch((err) => { + user.logout(); + reject(err); + }); + } + + return new Promise((resolve) => { + // 继续请求 + requests.push((token: string) => { + // 重新设置 token + Authorization = token; + next(); + resolve(); + }); + }); + } + } + } + + next(); + }); +} diff --git a/cool/service/sign.ts b/cool/service/sign.ts new file mode 100644 index 0000000..c4a7b15 --- /dev/null +++ b/cool/service/sign.ts @@ -0,0 +1,22 @@ +import md5 from "md5"; + +function useSign(params: any) { + const timestamp = new Date().getTime(); + + let arr = [`timestamp=${timestamp}`]; + + for (const i in params) { + arr.push(`${i}=${decodeURIComponent(params[i])}`); + } + + arr.sort(); + + const sign = md5(arr.join("&")); + + return { + timestamp, + sign, + }; +} + +export { useSign }; diff --git a/cool/store/dict.ts b/cool/store/dict.ts new file mode 100644 index 0000000..804d929 --- /dev/null +++ b/cool/store/dict.ts @@ -0,0 +1,66 @@ +import { defineStore } from "pinia"; +import { computed, reactive, toRaw } from "vue"; +import { deepTree } from "../utils"; +import { service } from "../service"; +import { isDev } from "/@/config"; +import { isString } from "lodash-es"; +import type { Dict } from "../types"; + +const useDictStore = defineStore("dict", () => { + // 对象数据 + const data = reactive({}); + + function get(name: string) { + return computed(() => data[name]).value || []; + } + + // 获取名称 + function getLabel(name: string | any[], value: any): string { + const arr: any[] = String(value)?.split(",") || []; + + return arr + .map((e) => { + return (isString(name) ? get(name) : name).find((a) => a.value == e)?.label; + }) + .filter(Boolean) + .join(","); + } + + // 刷新 + async function refresh(types?: string[]) { + return service.dict.info + .data({ + types, + }) + .then((res: Dict.Data) => { + const d: any = {}; + + for (const [i, arr] of Object.entries(res)) { + arr.forEach((e) => { + e.label = e.name; + e.value = e.value !== undefined ? e.value : e.id; + }); + + d[i] = deepTree(arr, "desc"); + } + + Object.assign(data, d); + + if (isDev) { + console.log("字典数据:"); + console.log(toRaw(data)); + } + + return data; + }); + } + + return { + data, + get, + getLabel, + refresh, + }; +}); + +export { useDictStore }; diff --git a/cool/store/index.ts b/cool/store/index.ts new file mode 100644 index 0000000..f84ee40 --- /dev/null +++ b/cool/store/index.ts @@ -0,0 +1,9 @@ +import { useUserStore } from "./user"; +import { useDictStore } from "./dict"; + +export function useStore() { + return { + user: useUserStore(), + dict: useDictStore(), + }; +} diff --git a/cool/store/user.ts b/cool/store/user.ts new file mode 100644 index 0000000..39b3c8c --- /dev/null +++ b/cool/store/user.ts @@ -0,0 +1,94 @@ +import { defineStore } from "pinia"; +import { ref } from "vue"; +import { deepMerge, storage } from "../utils"; +import { router } from "../router"; +import { service } from "../service"; +import type { User } from "../types"; + +// 本地缓存 +const data = storage.info(); + +const useUserStore = defineStore("user", function () { + // 标识 + const token = ref(data.token || ""); + + // 设置标识 + function setToken(data: User.Token) { + token.value = data.token; + + // 访问 + storage.set("token", data.token, data.expire - 5); + // 刷新 + storage.set("refreshToken", data.refreshToken, data.refreshExpire - 5); + } + + // 刷新标识 + async function refreshToken() { + return service.user.login + .refreshToken({ + refreshToken: storage.get("refreshToken"), + }) + .then((res) => { + setToken(res); + return res.token; + }); + } + + // 用户信息 + const info = ref(data.userInfo); + + // 设置用户信息 + function set(value: User.Info) { + info.value = value; + storage.set("userInfo", value); + } + + // 更新用户信息 + async function update(data: User.Info & { [key: string]: any }) { + set(deepMerge(info.value, data)); + return service.user.info.updatePerson(data); + } + + // 清除用户 + function clear() { + storage.remove("userInfo"); + storage.remove("token"); + storage.remove("refreshToken"); + token.value = ""; + info.value = undefined; + } + + // 退出 + function logout() { + clear(); + router.login({ reLaunch: true }); + } + + // 获取用户信息 + async function get() { + return service.user.info + .person() + .then((res) => { + if (res) { + set(res); + } + return res; + }) + .catch(() => { + logout(); + }); + } + + return { + token, + setToken, + refreshToken, + info, + get, + set, + update, + logout, + }; +}); + +export { useUserStore }; diff --git a/cool/types/index.d.ts b/cool/types/index.d.ts new file mode 100644 index 0000000..923b8ce --- /dev/null +++ b/cool/types/index.d.ts @@ -0,0 +1,43 @@ +export declare interface ModuleConfig { + name?: string; + description?: string; + order?: number; + demo?: { label: string; path: string }; + options?: { + [key: string]: any; + }; + onLoad?(options?: any): any; +} + +export declare interface Module extends ModuleConfig { + name: string; + options: { + [key: string]: any; + }; + [key: string]: any; +} + +export namespace User { + interface Token { + token: string; + expire: number; + refreshToken: string; + refreshExpire: number; + } + + interface Info extends Eps.UserInfoEntity {} +} + +export namespace Dict { + interface Item { + id: string; + label: string; + value: any; + children?: Item[]; + [key: string]: any; + } + + interface Data { + [key: string]: Item[]; + } +} diff --git a/cool/upload/comm.ts b/cool/upload/comm.ts new file mode 100644 index 0000000..c99fa46 --- /dev/null +++ b/cool/upload/comm.ts @@ -0,0 +1,48 @@ +import { isArray, has } from "lodash-es"; + +function parse(rules: string[], { url, size }: any) { + if (!url) { + return ""; + } + + let h = 0; + let w = 0; + + if (isArray(size)) { + h = size[0]; + w = size[1]; + } else if (has(size, "h")) { + h = size.h; + w = size.w; + + if (size.m) { + rules.push(`m_${size.m}`); + } + } else { + h = w = size; + } + + url += url.includes("?") ? "&" : "?"; + + if (h) { + rules.push(`h_${h}`); + } + + if (w) { + rules.push(`w_${w}`); + } + + return `${url}${rules.join(",")}`; +} + +type Size = number | number[] | { h?: number; w?: number; m?: string }; + +function videoPoster(url: string, size: Size) { + return parse(["x-oss-process=video/snapshot,t_1000,f_jpg,m_fast"], { url, size }); +} + +function resizeImage(url: string, size: Size) { + return parse(["x-oss-process=image/resize"], { url, size }); +} + +export { videoPoster, resizeImage }; diff --git a/cool/upload/index.ts b/cool/upload/index.ts new file mode 100644 index 0000000..df2bb2f --- /dev/null +++ b/cool/upload/index.ts @@ -0,0 +1,141 @@ +import dayjs from "dayjs"; +import { config } from "../../config"; +import { service } from "../service"; +import { basename, pathJoin, uuid } from "../utils"; +import { useStore } from "../store"; +import { videoPoster, resizeImage } from "./comm"; + +declare interface UploadCallback { + onProgressUpdate?(options: UniApp.OnProgressUpdateResult): void; + onTask?(task: UniApp.UploadTask): void; +} + +export async function upload(file: any, cb?: UploadCallback): Promise { + const { onProgressUpdate, onTask } = cb || {}; + + // 获取上传模式 + const { mode, type } = await service.base.comm.uploadMode(); + + // 用户缓存 + const { user } = useStore(); + + // 本地上传 + const isLocal = mode == "local"; + + // 文件名 + const fileName = uuid() + "_" + (file.name || basename(file.path)); + + // Key + const key = isLocal ? fileName : pathJoin("app", dayjs().format("YYYY-MM-DD"), fileName); + + // 多种上传请求 + return new Promise((resolve, reject) => { + // 上传文件 + function next({ host, preview, data }: { host: string; preview?: string; data?: any }) { + // 签名数据 + const fd = { + ...data, + key, + }; + + // 上传 + const task = uni.uploadFile({ + url: host, + filePath: file.path, + name: "file", + header: isLocal + ? { + Authorization: user.token, + } + : {}, + formData: fd, + success(res) { + if (isLocal) { + const { code, data, message } = JSON.parse(res.data); + if (code == 1000) { + resolve(data); + } else { + reject(message); + } + } else { + resolve(pathJoin(preview || host, fd.key)); + } + }, + fail(err) { + reject(err); + }, + }); + + if (onTask) { + onTask(task); + } + + if (onProgressUpdate) { + task.onProgressUpdate(onProgressUpdate); + } + } + + if (isLocal) { + next({ + host: config.baseUrl + "/app/base/comm/upload", + }); + } else { + service.base.comm + .upload( + type == "aws" + ? { + key, + } + : {} + ) + .then((res) => { + switch (type) { + // 腾讯 + case "cos": + next({ + host: res.url, + data: res.credentials, + }); + break; + // 阿里 + case "oss": + next({ + host: res.host, + data: { + OSSAccessKeyId: res.OSSAccessKeyId, + policy: res.policy, + signature: res.signature, + }, + }); + break; + // 七牛 + case "qiniu": + next({ + host: res.uploadUrl, + preview: res.publicDomain, + data: { + token: res.token, + }, + }); + break; + // aws + case "aws": + next({ + host: res.url, + data: res.fields, + }); + break; + } + }) + .catch(reject); + } + }); +} + +export function useUpload() { + return { + upload, + videoPoster, + resizeImage, + }; +} diff --git a/cool/utils/canvas.ts b/cool/utils/canvas.ts new file mode 100644 index 0000000..e6cecc2 --- /dev/null +++ b/cool/utils/canvas.ts @@ -0,0 +1,603 @@ +import { getCurrentInstance } from "vue"; +import { isEmpty, isString, cloneDeep, isObject } from "lodash-es"; + +// 渲染参数 +declare interface RenderOptions { + x: number; + y: number; + height?: number; + width?: number; + [key: string]: any; +} + +// 文本渲染参数 +declare interface TextRenderOptions extends RenderOptions { + text: string; + color?: string; + fontSize?: number; + textAlign?: "left" | "right" | "center"; + overflow?: "ellipsis"; + lineClamp?: number; + letterSpace?: number; + lineHeight?: number; +} + +// 图片渲染参数 +declare interface ImageRenderOptions extends RenderOptions { + url: string; + mode?: "aspectFill" | "aspectFit"; + radius?: number; +} + +// 块渲染参数 +declare interface DivRenderOptions extends RenderOptions { + radius?: number; + backgroundColor?: string; + border?: { + width: number; + color: string; + }; +} + +// 导出图片参数 +declare interface CreateImageOptins { + x?: number; + y?: number; + width?: number; + height?: number; + destWidth?: number; + destHeight?: number; + fileType?: "jpg" | "png"; + quality?: number; +} + +class Canvas { + ctx: any; + canvasId: any; + scope: any; + renderQuene: any; + imageQueue: any; + + constructor(canvasId: string) { + // 绘图上下文 + this.ctx = null; + + // canvas id + this.canvasId = canvasId; + + // 当前页面作用域 + const { proxy }: any = getCurrentInstance(); + this.scope = proxy; + + // 渲染队列 + this.renderQuene = []; + + // 图片队列 + this.imageQueue = []; + + // 创建画布 + this.create(); + } + + // 创建画布 + create() { + this.ctx = uni.createCanvasContext(this.canvasId, this.scope); + return this; + } + + // 块 + div(options: DivRenderOptions) { + let render = () => { + this.divRender(options); + }; + this.renderQuene.push(render); + return this; + } + + // 文本 + text(options: TextRenderOptions) { + let render = () => { + this.textRender(options); + }; + this.renderQuene.push(render); + return this; + } + + // 图片 + image(options: ImageRenderOptions) { + let render = () => { + this.imageRender(options); + }; + this.imageQueue.push(options); + this.renderQuene.push(render); + return this; + } + + // 绘画 + draw(save = false) { + return new Promise((resolve) => { + let next = () => { + this.render(); + this.ctx.draw(save, () => { + resolve(true); + }); + }; + + if (!isEmpty(this.imageQueue)) { + this.preLoadImage().then(next); + } else { + next(); + } + }); + } + + // 生成图片 + createImage(options?: CreateImageOptins): Promise { + return new Promise((resolve, reject) => { + let data = { + canvasId: this.canvasId, + ...options, + success: (res: any) => { + // #ifdef MP-ALIPAY + resolve(res.apFilePath); + // #endif + + // #ifndef MP-ALIPAY + resolve(res.tempFilePath); + // #endif + }, + fail: reject, + }; + + // #ifdef MP-ALIPAY + this.ctx.toTempFilePath(data); + // #endif + + // #ifndef MP-ALIPAY + uni.canvasToTempFilePath(data, this.scope); + // #endif + }); + } + + // 保存图片 + saveImage(options?: CreateImageOptins) { + uni.showLoading({ + title: "图片下载中...", + }); + this.createImage(options).then((path: any) => { + return new Promise((resolve) => { + uni.hideLoading(); + uni.saveImageToPhotosAlbum({ + filePath: path, + success: () => { + uni.showToast({ + title: "保存图片成功", + }); + resolve(path); + }, + fail: (err) => { + // #ifdef MP-ALIPAY + uni.showToast({ + title: "保存图片成功", + }); + // #endif + + // #ifndef MP-ALIPAY + uni.showToast({ + title: "保存图片失败", + icon: "none", + }); + // #endif + }, + }); + }); + }); + } + + // 预览图片 + previewImage(options?: CreateImageOptins) { + this.createImage(options).then((url: string | any) => { + uni.previewImage({ + urls: [url], + }); + }); + } + + // 下载图片 + downLoadImage(item: any) { + return new Promise((resolve, reject) => { + if (!item.url) { + return reject("url 不能为空"); + } + + // 处理base64 + // #ifdef MP + if (item.url.indexOf("data:image") >= 0) { + let extName = item.url.match(/data\:\S+\/(\S+);/); + if (extName) { + extName = extName[1]; + } + const fs = uni.getFileSystemManager(); + const fileName = Date.now() + "." + extName; + // @ts-ignore + const filePath = wx.env.USER_DATA_PATH + "/" + fileName; + + return fs.writeFile({ + filePath, + data: item.url.replace(/^data:\S+\/\S+;base64,/, ""), + encoding: "base64", + success: () => { + item.url = filePath; + resolve(filePath); + }, + }); + } + // #endif + + // 是否网络图片 + const isHttp = item.url.includes("http"); + + uni.getImageInfo({ + src: item.url, + success: (result) => { + item.sheight = result.height; + item.swidth = result.width; + + if (isHttp) { + item.url = result.path; + } + + resolve(item.url); + }, + fail: (err) => { + console.log(err, item.url); + reject(err); + }, + }); + + return 1; + }); + } + + // 预加载图片 + async preLoadImage() { + await Promise.all(this.imageQueue.map(this.downLoadImage)); + } + + // 设置背景颜色 + setBackground(options: any) { + if (!options) return null; + + let backgroundColor; + + if (!isString(options)) { + backgroundColor = options; + } + + if (isString(options.backgroundColor)) { + backgroundColor = options.backgroundColor; + } + + if (isObject(options.backgroundColor)) { + let { startX, startY, endX, endY, gradient } = options.backgroundColor; + const rgb = this.ctx.createLinearGradient(startX, startY, endX, endY); + for (let i = 0, l = gradient.length; i < l; i++) { + rgb.addColorStop(gradient[i].step, gradient[i].color); + } + backgroundColor = rgb; + } + + this.ctx.setFillStyle(backgroundColor); + + return this; + } + + // 设置边框 + setBorder(options: any) { + if (!options.border) return this; + + let { x, y, width: w, height: h, border, radius: r } = options; + + if (border.width) { + this.ctx.setLineWidth(border.width); + } + + if (border.color) { + this.ctx.setStrokeStyle(border.color); + } + + // 偏移距离 + let p = border.width / 2; + + // 是否有圆角 + if (r) { + this.drawRadiusRoute(x - p, y - p, w + 2 * p, h + 2 * p, r + p); + this.ctx.stroke(); + } else { + this.ctx.strokeRect(x - p, y - p, w + 2 * p, h + 2 * p); + } + + return this; + } + + // 设置缩放,旋转 + setTransform(options: any) { + if (options.scale) { + } + if (options.rotate) { + } + } + + // 带有圆角的路径绘制 + drawRadiusRoute(x: number, y: number, w: number, h: number, r: number) { + this.ctx.beginPath(); + this.ctx.moveTo(x + r, y, y); + this.ctx.lineTo(x + w - r, y); + this.ctx.arc(x + w - r, y + r, r, 1.5 * Math.PI, 0); + this.ctx.lineTo(x + w, y + h - r); + this.ctx.arc(x + w - r, y + h - r, r, 0, 0.5 * Math.PI); + this.ctx.lineTo(x + r, y + h); + this.ctx.arc(x + r, y + h - r, r, 0.5 * Math.PI, Math.PI); + this.ctx.lineTo(x, y + r); + this.ctx.arc(x + r, y + r, r, Math.PI, 1.5 * Math.PI); + this.ctx.closePath(); + } + + // 裁剪图片 + cropImage( + mode: "aspectFill" | "aspectFit", + width: number, + height: number, + sWidth: number, + sHeight: number, + x: number, + y: number + ) { + let cx, cy, cw, ch, sx, sy, sw, sh; + switch (mode) { + case "aspectFill": + if (width <= height) { + let p = width / sWidth; + cw = width; + ch = sHeight * p; + cx = 0; + cy = (height - ch) / 2; + } else { + let p = height / sHeight; + cw = sWidth * p; + ch = height; + cx = (width - cw) / 2; + cy = 0; + } + break; + case "aspectFit": + if (width <= height) { + let p = height / sHeight; + sw = width / p; + sh = sHeight; + sx = x + (sWidth - sw) / 2; + sy = y; + } else { + let p = width / sWidth; + sw = sWidth; + sh = height / p; + sx = x; + sy = y + (sHeight - sh) / 2; + } + break; + } + return { cx, cy, cw, ch, sx, sy, sw, sh }; + } + + // 获取文本内容 + getTextRows({ + text, + fontSize = 14, + width = 100, + lineClamp = 1, + overflow, + letterSpace = 0, + }: any) { + let arr: any[] = [[]]; + let a = 0; + + for (let i = 0; i < text.length; i++) { + let b = this.getFontPx(text[i], { fontSize, letterSpace }); + + if (a + b > width) { + a = b; + arr.push(text[i]); + } else { + // 最后一行且设置超出省略号 + if ( + overflow == "ellipsis" && + arr.length == lineClamp && + a + 3 * this.getFontPx(".", { fontSize, letterSpace }) > width - 5 + ) { + arr[arr.length - 1] += "..."; + break; + } else { + a += b; + arr[arr.length - 1] += text[i]; + } + } + } + + return arr; + } + + // 获取单个字体像素大小 + getFontPx(text: string, { fontSize = 14, letterSpace }: any) { + if (!text) { + return fontSize / 2 + fontSize / 14 + letterSpace; + } + + let ch = text.charCodeAt(0); + + if ((ch >= 0x0001 && ch <= 0x007e) || (0xff60 <= ch && ch <= 0xff9f)) { + return fontSize / 2 + fontSize / 14 + letterSpace; + } else { + return fontSize + letterSpace; + } + } + + // 渲染块 + divRender(options: DivRenderOptions) { + this.ctx.save(); + this.setBackground(options); + this.setBorder(options); + this.setTransform(options); + + // 区分是否有圆角采用不同模式渲染 + if (options.radius) { + let { x, y } = options; + let w = options.width || 0; + let h = options.height || 0; + let r = options.radius || 0; + // 画路径 + this.drawRadiusRoute(x, y, w, h, r); + // 填充 + this.ctx.fill(); + } else { + this.ctx.fillRect(options.x, options.y, options.width, options.height); + } + this.ctx.restore(); + } + + // 渲染文本 + textRender(options: TextRenderOptions) { + let { + fontSize = 14, + textAlign, + width, + color = "#000000", + x, + y, + letterSpace, + lineHeight = 14, + } = options || {}; + + this.ctx.save(); + + // 设置字体大小 + this.ctx.setFontSize(fontSize); + + // 设置字体颜色 + this.ctx.setFillStyle(color); + + // 获取文本内容 + let rows = this.getTextRows(options); + + // 获取文本行高 + let lh = lineHeight - fontSize; + + // 左偏移 + let offsetLeft = 0; + + // 字体对齐 + if (textAlign && width) { + this.ctx.textAlign = textAlign; + + switch (textAlign) { + case "left": + break; + case "center": + offsetLeft = width / 2; + break; + case "right": + offsetLeft = width; + break; + } + } + + // 逐行写入 + for (let i = 0; i < rows.length; i++) { + let d = offsetLeft; + + if (letterSpace) { + for (let j = 0; j < rows[i].length; j++) { + // 写入文字 + this.ctx.fillText(rows[i][j], x + d, (i + 1) * fontSize + y + lh * i); + + // 设置偏移 + d += this.getFontPx(rows[i][j], options); + } + } else { + // 写入文字 + this.ctx.fillText(rows[i], x + offsetLeft, (i + 1) * fontSize + y + lh * i); + } + } + + this.ctx.restore(); + } + + // 渲染图片 + imageRender(options: ImageRenderOptions) { + this.ctx.save(); + + if (options.radius) { + // 画路径 + this.drawRadiusRoute( + options.x, + options.y, + options.width || options.swidth, + options.height || options.sHeight, + options.radius + ); + // 填充 + this.ctx.fill(); + // 裁剪 + this.ctx.clip(); + } + let temp = cloneDeep(this.imageQueue[0]); + + if (options.mode) { + let { cx, cy, cw, ch, sx, sy, sw, sh } = this.cropImage( + options.mode, + temp.swidth, + temp.sheight, + temp.width, + temp.height, + temp.x, + temp.y + ); + switch (options.mode) { + case "aspectFit": + this.ctx.drawImage(temp.url, sx, sy, sw, sh); + break; + case "aspectFill": + this.ctx.drawImage( + temp.url, + cx, + cy, + cw, + ch, + temp.x, + temp.y, + temp.width, + temp.height + ); + break; + } + } else { + this.ctx.drawImage( + temp.url, + temp.x, + temp.y, + temp.width || temp.swidth, + temp.height || temp.sheight + ); + } + this.imageQueue.shift(); + this.ctx.restore(); + } + + // 渲染全部 + render() { + this.renderQuene.forEach((ele: any) => { + ele(); + }); + } +} + +export { Canvas }; diff --git a/cool/utils/comm.ts b/cool/utils/comm.ts new file mode 100644 index 0000000..ff4619f --- /dev/null +++ b/cool/utils/comm.ts @@ -0,0 +1,163 @@ +import { orderBy } from "lodash-es"; + +export const { platform } = uni.getSystemInfoSync(); + +// 是否安卓 +export const isAndroid = platform == "android"; + +// 是否苹果 +export const isIos = platform == "ios"; + +// 是否小数 +export function isDecimal(value: any): boolean { + return String(value).length - String(value).indexOf(".") + 1 > 0; +} + +// 首字母大写 +export function firstUpperCase(value: string): string { + return value.replace(/\b(\w)(\w*)/g, function ($0, $1, $2) { + return $1.toUpperCase() + $2; + }); +} + +// 深度合并 +export function deepMerge(a: any, b: any) { + let k; + for (k in b) { + a[k] = + a[k] && a[k].toString() === "[object Object]" ? deepMerge(a[k], b[k]) : (a[k] = b[k]); + } + return a; +} + +// 获取地址栏参数 +export function getUrlParam(name: string): string | null { + const reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); + const r = window.location.search.substr(1).match(reg); + if (r != null) return decodeURIComponent(r[2]); + return null; +} + +// 列表转树形 +export function deepTree(list: any[], sort?: "desc" | "asc"): any[] { + const newList: any[] = []; + const map: any = {}; + + orderBy(list, "orderNum", sort) + .map((e) => { + map[e.id] = e; + return e; + }) + .forEach((e) => { + const parent = map[e.parentId]; + + if (parent) { + (parent.children || (parent.children = [])).push(e); + } else { + newList.push(e); + } + }); + + return newList; +} + +// 路径转对象 +export function path2Obj(list: any[]) { + const data: any = {}; + + list.forEach(({ path, value }) => { + const arr: string[] = path.split("/"); + const parents = arr.slice(0, arr.length - 1); + const name = basename(path).replace(".ts", ""); + + let curr = data; + + parents.forEach((k) => { + if (!curr[k]) { + curr[k] = {}; + } + + curr = curr[k]; + }); + + curr[name] = value; + }); + + return data; +} + +// 路径拼接 +export function pathJoin(...parts: string[]): string { + if (parts.length === 0) { + return ""; + } + + const firstPart = parts[0]; + let isAbsolute = false; + + // 检查第一个部分是否以 "http" 开头,以确定路径类型(绝对还是相对) + if (firstPart.startsWith("http")) { + isAbsolute = true; + } + + // 标准化路径,去除任何开头或结尾的斜杠 + const normalizedParts = parts.map((part) => part.replace(/(^\/+|\/+$)/g, "")); + + if (isAbsolute) { + // 如果是绝对路径,使用斜杠连接部分 + return normalizedParts.join("/"); + } else { + // 如果是相对路径,使用平台特定的分隔符连接部分 + return normalizedParts.join("/"); + } +} + +// 文件名 +export function filename(path: string): string { + return basename(path.substring(0, path.lastIndexOf("."))); +} + +// 路径名称 +export function basename(path: string): string { + let index = path.lastIndexOf("/"); + index = index > -1 ? index : path.lastIndexOf("\\"); + if (index < 0) { + return path; + } + return path.substring(index + 1); +} + +// 文件扩展名 +export function extname(path: string): string { + return path.substring((path || "").lastIndexOf(".") + 1); +} + +// 横杠转驼峰 +export function toCamel(str: string): string { + return str.replace(/([^-])(?:-+([^-]))/g, function ($0, $1, $2) { + return $1 + $2.toUpperCase(); + }); +} + +// uuid +export function uuid(): string { + const s: any[] = []; + const hexDigits = "0123456789abcdef"; + for (let i = 0; i < 36; i++) { + s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); + } + s[14] = "4"; + s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); + s[8] = s[13] = s[18] = s[23] = "-"; + + return s.join(""); +} + +// 延迟 +export function sleep(duration: number) { + return new Promise((resolve) => { + setTimeout(() => { + resolve(true); + }, duration); + }); +} diff --git a/cool/utils/index.ts b/cool/utils/index.ts new file mode 100644 index 0000000..873f805 --- /dev/null +++ b/cool/utils/index.ts @@ -0,0 +1,4 @@ +export * from "./comm"; +export * from "./ui"; +export * from "./canvas"; +export * from "./storage"; diff --git a/cool/utils/storage.ts b/cool/utils/storage.ts new file mode 100644 index 0000000..d12606b --- /dev/null +++ b/cool/utils/storage.ts @@ -0,0 +1,75 @@ +export const storage = { + // 后缀标识 + suffix: "_deadtime", + + /** + * 获取 + * @param {*} key 关键字 + */ + get(key: string): any { + return uni.getStorageSync(key); + }, + + /** + * 获取全部 + */ + info() { + const { keys } = uni.getStorageInfoSync(); + const d: any = {}; + + keys.forEach((e: string) => { + d[e] = uni.getStorageSync(e); + }); + + return d; + }, + + /** + * 设置 + * @param {*} key 关键字 + * @param {*} value 值 + * @param {*} expires 过期时间 + */ + set(key: string, value: any, expires?: number): void { + uni.setStorageSync(key, value); + + if (expires) { + uni.setStorageSync( + `${key}${this.suffix}`, + Date.parse(String(new Date())) + expires * 1000 + ); + } + }, + + /** + * 是否过期 + * @param {*} key 关键字 + */ + isExpired(key: string): boolean { + return uni.getStorageSync(`${key}${this.suffix}`) - Date.parse(String(new Date())) <= 0; + }, + + /** + * 删除 + * @param {*} key 关键字 + */ + remove(key: string) { + return uni.removeStorageSync(key); + }, + + /** + * 清理 + */ + clear() { + uni.clearStorageSync(); + }, + + /** + * 获取一次后删除 + */ + once(key: string) { + const value = this.get(key); + this.remove(key); + return value; + }, +}; diff --git a/cool/utils/ui.ts b/cool/utils/ui.ts new file mode 100644 index 0000000..16b94e9 --- /dev/null +++ b/cool/utils/ui.ts @@ -0,0 +1,78 @@ +import { isArray, isEmpty, isNumber } from "lodash-es"; +import { computed, getCurrentInstance, nextTick, ref } from "vue"; + +// 获取父组件 +export function getParent(name: string, k1: string[], k2?: string[]) { + const { proxy }: any = getCurrentInstance(); + + const d = ref(); + let n = 10; + + const next = () => { + let parent = proxy.$parent; + + while (parent) { + if (parent.$options.name !== name) { + parent = parent.$parent; + } else { + if (isArray(k2)) { + nextTick(() => { + const child: any = {}; + + (k2 || []).map((key: string) => { + if (proxy[key]) { + child[key] = proxy[key]; + } + }); + + if (!parent.__children) { + parent.__children = []; + } + + if (!isEmpty(child)) { + parent.__children.push(child); + } + }); + } + + return (k1 || []).reduce((res: any, key: string) => { + res[key] = parent[key]; + + return res; + }, {}); + } + } + + // if (!d.value && n-- > 0) { + // setTimeout(() => { + // d.value = next(); + // }, 50); + // } + + return parent || d.value; + }; + + return computed(() => next()); +} + +// 获取元素位置信息 +export async function getRect(selector: string): Promise { + return new Promise((resolve) => { + uni.createSelectorQuery() + .select(selector) + .boundingClientRect((res) => { + resolve(res); + }) + .exec(); + }); +} + +// 解析rpx +export function parseRpx(val: any): string { + return isArray(val) ? val.map(parseRpx).join(" ") : isNumber(val) ? `${val}rpx` : val; +} + +// px 转 rpx +export function px2Rpx(px: number) { + return px / (uni.upx2px(100) / 100); +} diff --git a/hooks/index.ts b/hooks/index.ts new file mode 100644 index 0000000..1d68a8c --- /dev/null +++ b/hooks/index.ts @@ -0,0 +1,29 @@ +import { defineStore } from "pinia"; +import { ref } from "vue"; +import { service } from "/@/cool"; + +export const useAddress = defineStore("address", () => { + const info = ref(); + + function set(data: Eps.UserAddressEntity) { + info.value = data; + } + + function getDefault() { + if (!info.value || info.value?.isDefault) { + service.user.address.default().then((res) => { + info.value = res; + }); + } + } + + return { + info, + set, + getDefault, + }; +}); + +export * from "./shopping-cart"; +export * from "./spec"; +export * from "./order"; diff --git a/hooks/order.ts b/hooks/order.ts new file mode 100644 index 0000000..f55f85d --- /dev/null +++ b/hooks/order.ts @@ -0,0 +1,47 @@ +import { service, useWx } from "/@/cool"; + +export function useOrder() { + const wx = useWx(); + + const payTypes = [ + { + label: "微信支付", + value: 1, + key: "wxpay", + icon: "/static/icon/wxpay.png", + }, + // { + // label: "支付宝支付", + // value: 2, + // key: "alipay", + // icon: "/static/icon/alipay.png", + // }, + ]; + + async function toPay(orderId: number, type = "wxpay") { + // #ifdef MP-WEIXIN + return service.order.pay.wxMiniPay({ orderId }).then((res) => { + return wx.miniPay(res.data); + }); + // #endif + + // #ifdef H5 + if (wx.isWxBrowser()) { + return service.order.pay.wxMpPay({ orderId }).then((res) => { + return wx.mpPay(res.data); + }); + } + // #endif + + // #ifdef APP + return service.order.pay.wxAppPay({ orderId }).then((res) => { + return wx.appPay(res.data); + }); + // #endif + } + + return { + toPay, + payTypes, + }; +} diff --git a/hooks/shopping-cart.ts b/hooks/shopping-cart.ts new file mode 100644 index 0000000..e40bc85 --- /dev/null +++ b/hooks/shopping-cart.ts @@ -0,0 +1,70 @@ +import { defineStore } from "pinia"; +import { computed, ref, watch } from "vue"; +import { storage } from "/@/cool"; +import { uuid } from "/@/cool/utils"; + +// 购物车 +export const useShoppingCart = defineStore("shopping-cart", () => { + const list = ref(storage.get("shopping-cart.list") || []); + + // 购物车数量 + const num = computed(() => { + return list.value.length; + }); + + // 数量+1 + function add(data: OrderGoods) { + const d = list.value.find((e) => e.spec?.id == data.spec?.id); + + if (d) { + // 判定库存 + d.count += data.count || 1; + + if (d.count > data.spec.stock!) { + d.count = data.spec.stock || 1; + } + } else { + list.value.push({ + ...data, + id: uuid(), + }); + } + } + + // 删除规格 + function del(id: string) { + const i = list.value.findIndex((e) => e.id == id); + + if (i >= 0) { + list.value.splice(i, 1); + } + } + + // 删除规格根据 specId + function delBySpecId(id: number) { + const i = list.value.findIndex((e) => e.spec?.id == id); + + if (i >= 0) { + list.value.splice(i, 1); + } + } + + // 监听更新 + watch( + list, + (val) => { + storage.set("shopping-cart.list", val); + }, + { + deep: true, + }, + ); + + return { + list, + num, + add, + del, + delBySpecId, + }; +}); diff --git a/hooks/spec.ts b/hooks/spec.ts new file mode 100644 index 0000000..02fb13d --- /dev/null +++ b/hooks/spec.ts @@ -0,0 +1,115 @@ +import { defineStore } from "pinia"; +import { computed, ref } from "vue"; + +type Action = "select" | "spCart" | "buy" | "edit"; + +export const useSpec = defineStore("goods.spec", () => { + const visible = ref(false); + + // 打开类型 + const action = ref("select"); + + // 商品信息 + const goods = ref(); + + // 已选规格信息 + const info = ref(); + + // 已选数量 + const num = ref(1); + + // 指定规格id + const specId = ref(); + + // 回调函数 + let cb: ((action: Action) => void) | undefined; + + // 选中文案 + const text = computed(() => { + return info.value ? `已选:${info.value.name}` : "选择规格"; + }); + + // 打开弹窗 + function open(options: { + action: Action; + goods: Eps.GoodsInfoEntity; + spec?: Eps.GoodsSpecEntity; + specId?: number; + count?: number; + item?: OrderGoods; + callback?: typeof cb; + }) { + if (!options.goods) { + return false; + } + + visible.value = true; + action.value = options.action || "select"; + goods.value = options.goods; + specId.value = options.specId || options.spec?.id || specId.value; + + if (options.spec) { + info.value = options.spec; + } + + cb = options.callback; + + if (options.action == "edit") { + num.value = options.count || 0; + } + } + + // 关闭弹窗 + function close() { + visible.value = false; + } + + // 设置选中规格 + function set(data?: Eps.GoodsSpecEntity) { + info.value = data; + setId(data?.id!); + } + + // 设置规格id + function setId(id: number) { + specId.value = id; + } + + // 设置数量 + function setNum(val?: number) { + num.value = val || 0; + } + + // 回调 + function emit(action: Action) { + if (cb) { + cb(action); + } + } + + // 清空选项 + function clear() { + num.value = 1; + info.value = undefined; + goods.value = undefined; + specId.value = undefined; + cb = undefined; + } + + return { + visible, + action, + goods, + info, + emit, + num, + setNum, + specId, + text, + open, + close, + set, + setId, + clear, + }; +}); diff --git a/index.html b/index.html new file mode 100644 index 0000000..b61f63e --- /dev/null +++ b/index.html @@ -0,0 +1,14 @@ + + + + + + + + + + +
+ + + diff --git a/main.js b/main.js new file mode 100644 index 0000000..d22761a --- /dev/null +++ b/main.js @@ -0,0 +1,18 @@ +import { createSSRApp } from "vue"; +import { bootstrap } from "/@/cool/bootstrap"; +import App from "./App.vue"; +import "./router"; + +export function createApp() { + const app = createSSRApp(App); + + // 启动 + bootstrap(app); + + // 隐藏底部导航栏 + uni.hideTabBar(); + + return { + app, + }; +} diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..4f9e44b --- /dev/null +++ b/manifest.json @@ -0,0 +1,174 @@ +{ + "name" : "酷卖", + "appid" : "__UNI__75A96B5", + "description" : "", + "versionName" : "1.0.0", + "versionCode" : 100, + "transformPx" : false, + "app-plus" : { + "usingComponents" : true, + "splashscreen" : { + "alwaysShowBeforeRender" : true, + "waiting" : true, + "autoclose" : true, + "delay" : 0 + }, + "modules" : { + "VideoPlayer" : {}, + "Share" : {}, + "Payment" : {}, + "OAuth" : {}, + "Geolocation" : {}, + "Camera" : {} + }, + "distribute" : { + "android" : { + "permissions" : [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ] + }, + "ios" : { + "capabilities" : { + "entitlements" : { + "com.apple.developer.associated-domains" : [] + } + }, + "idfa" : true, + "privacyDescription" : { + "NSUserTrackingUsageDescription" : "请放心,开启权限不会获取您在其他站点的隐私信息,该权限仅用于标识设备并保障服务安全与提示浏览体验" + } + }, + "sdkConfigs" : { + "payment" : { + "alipay" : { + "__platform__" : [ "ios", "android" ] + }, + "weixin" : { + "__platform__" : [ "ios", "android" ], + "appid" : "wx348f72db1512fa2e", + "UniversalLinks" : "" + } + }, + "ad" : {}, + "share" : { + "weixin" : { + "appid" : "wx348f72db1512fa2e", + "UniversalLinks" : "" + } + }, + "oauth" : { + "weixin" : { + "appid" : "wx348f72db1512fa2e", + "appsecret" : "test", + "UniversalLinks" : "" + }, + "apple" : {} + }, + "geolocation" : { + "system" : { + "__platform__" : [ "ios", "android" ] + } + }, + "push" : { + "unipush" : {} + }, + "maps" : {} + }, + "icons" : { + "android" : { + "hdpi" : "unpackage/res/icons/72x72.png", + "xhdpi" : "unpackage/res/icons/96x96.png", + "xxhdpi" : "unpackage/res/icons/144x144.png", + "xxxhdpi" : "unpackage/res/icons/192x192.png" + }, + "ios" : { + "appstore" : "unpackage/res/icons/1024x1024.png", + "ipad" : { + "app" : "unpackage/res/icons/76x76.png", + "app@2x" : "unpackage/res/icons/152x152.png", + "notification" : "unpackage/res/icons/20x20.png", + "notification@2x" : "unpackage/res/icons/40x40.png", + "proapp@2x" : "unpackage/res/icons/167x167.png", + "settings" : "unpackage/res/icons/29x29.png", + "settings@2x" : "unpackage/res/icons/58x58.png", + "spotlight" : "unpackage/res/icons/40x40.png", + "spotlight@2x" : "unpackage/res/icons/80x80.png" + }, + "iphone" : { + "app@2x" : "unpackage/res/icons/120x120.png", + "app@3x" : "unpackage/res/icons/180x180.png", + "notification@2x" : "unpackage/res/icons/40x40.png", + "notification@3x" : "unpackage/res/icons/60x60.png", + "settings@2x" : "unpackage/res/icons/58x58.png", + "settings@3x" : "unpackage/res/icons/87x87.png", + "spotlight@2x" : "unpackage/res/icons/80x80.png", + "spotlight@3x" : "unpackage/res/icons/120x120.png" + } + } + }, + "splashscreen" : { + "useOriginalMsgbox" : true + } + }, + "safearea" : { + "bottom" : { + "offset" : "none" + } + }, + "uniStatistics" : { + "enable" : true + } + }, + "quickapp" : {}, + "mp-weixin" : { + "appid" : "wxdebc4de0b5584ca4", + "setting" : { + "urlCheck" : false, + "es6" : true + }, + "usingComponents" : true + }, + "mp-alipay" : { + "usingComponents" : true + }, + "mp-baidu" : { + "usingComponents" : true + }, + "mp-toutiao" : { + "usingComponents" : true + }, + "uniStatistics" : { + "enable" : false + }, + "vueVersion" : "3", + "h5" : { + "router" : { + "base" : "./", + "mode" : "hash" + }, + "devServer" : { + "https" : false + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..bce91e0 --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "cool-uni", + "version": "7.3.0", + "license": "MIT", + "dependencies": { + "@dcloudio/uni-app": "3.0.0-3081220230817001", + "@hyoga/uni-socket.io": "^3.0.4", + "dayjs": "^1.11.10", + "js-pinyin": "^0.2.5", + "lodash-es": "^4.17.21", + "md5": "^2.3.0", + "pinia": "^2.1.7", + "vue": "^3.4.21", + "weixin-js-sdk": "^1.6.5" + }, + "engines": { + "node": ">= 16" + }, + "devDependencies": { + "@cool-vue/vite-plugin": "7.1.3", + "@dcloudio/types": "^3.4.8", + "@types/lodash-es": "^4.17.12", + "@types/md5": "^2.3.2", + "@types/node": "^20.11.26", + "@vue/tsconfig": "^0.5.1", + "typescript": "^5.2.2", + "vite": "^5.1.6" + } +} diff --git a/pages.json b/pages.json new file mode 100644 index 0000000..3692d75 --- /dev/null +++ b/pages.json @@ -0,0 +1,268 @@ +{ + "pages": [ + { + "path": "pages/index/home", + "style": { + "enablePullDownRefresh": true + } + }, + { + "path": "pages/index/category", + "style": { + "disableScroll": true, + "navigationBarTitleText": "分类" + } + }, + { + "path": "pages/index/shopping-cart", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "购物车" + } + }, + { + "path": "pages/index/my", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "我的", + "navigationBarTextStyle": "white" + } + } + ], + "subPackages": [ + { + "root": "uni_modules/cool-app/pages", + "pages": [ + { + "path": "version/demo", + "style": { + "navigationBarTitleText": "版本升级" + } + }, + { + "path": "complain/detail", + "style": { + "navigationBarTitleText": "投诉详情" + } + }, + { + "path": "complain/list", + "style": { + "navigationBarTitleText": "投诉列表" + } + }, + { + "path": "complain/submit", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "feedback/detail", + "style": { + "navigationBarTitleText": "反馈详情" + } + }, + { + "path": "feedback/list", + "style": { + "navigationBarTitleText": "反馈列表" + } + }, + { + "path": "feedback/submit", + "style": { + "navigationStyle": "custom" + } + } + ], + "isTemp": true + }, + { + "root": "uni_modules/cool-cs/pages", + "pages": [ + { + "path": "chat", + "style": { + "navigationBarTitleText": "客服聊天" + } + } + ], + "isTemp": true + }, + { + "root": "pages/market", + "pages": [ + { + "path": "coupon", + "style": { + "navigationBarTitleText": "我的优惠券", + "enablePullDownRefresh": true + } + } + ] + }, + { + "root": "pages/order", + "pages": [ + { + "path": "refund", + "style": { + "navigationBarTitleText": "退款申请" + } + }, + { + "path": "comment", + "style": { + "navigationBarTitleText": "商品评价" + } + }, + { + "path": "logistics", + "style": { + "navigationBarTitleText": "物流详情", + "enablePullDownRefresh": true + } + }, + { + "path": "list", + "style": { + "navigationBarTitleText": "订单列表", + "enablePullDownRefresh": true + } + }, + { + "path": "detail", + "style": { + "navigationBarTitleText": "订单详情", + "enablePullDownRefresh": true, + "navigationStyle": "custom" + } + }, + { + "path": "submit", + "style": { + "navigationBarTitleText": "订单提交" + } + } + ] + }, + { + "root": "pages/goods", + "pages": [ + { + "path": "search", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "list", + "style": { + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "detail", + "style": { + "navigationStyle": "custom", + "enablePullDownRefresh": true + } + }, + { + "path": "comment", + "style": { + "navigationBarTitleText": "商品评价" + } + } + ] + }, + { + "root": "pages/user", + "pages": [ + { + "path": "address-list", + "style": { + "navigationBarTitleText": "收货地址", + "enablePullDownRefresh": true + } + }, + { + "path": "address-edit", + "style": { + "navigationBarTitleText": "" + } + }, + { + "path": "doc", + "style": { + "navigationBarTitleText": "" + } + }, + { + "path": "set", + "style": { + "navigationBarTitleText": "设置" + } + }, + { + "path": "edit", + "style": { + "navigationBarTitleText": "编辑" + } + }, + { + "path": "login", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "captcha", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "about", + "style": { + "navigationBarTitleText": "" + } + } + ] + } + ], + "globalStyle": { + "navigationBarTextStyle": "black", + "navigationBarTitleText": "酷卖", + "navigationBarBackgroundColor": "#ffffff", + "backgroundColor": "#f6f7fa" + }, + "tabBar": { + "backgroundColor": "#ffffff", + "borderStyle": "white", + "list": [ + { + "pagePath": "pages/index/home", + "iconPath": "static/icon/tabbar/home.png", + "selectedIconPath": "static/icon/tabbar/home2.png" + }, + { + "pagePath": "pages/index/category", + "iconPath": "static/icon/tabbar/category.png", + "selectedIconPath": "static/icon/tabbar/category2.png" + }, + { + "pagePath": "pages/index/shopping-cart", + "iconPath": "static/icon/tabbar/shopping-cart.png", + "selectedIconPath": "static/icon/tabbar/shopping-cart2.png" + }, + { + "pagePath": "pages/index/my", + "iconPath": "static/icon/tabbar/my.png", + "selectedIconPath": "static/icon/tabbar/my2.png" + } + ] + } +} \ No newline at end of file diff --git a/pages/goods/comment.vue b/pages/goods/comment.vue new file mode 100644 index 0000000..8369a57 --- /dev/null +++ b/pages/goods/comment.vue @@ -0,0 +1,57 @@ + + + + + diff --git a/pages/goods/components/comment-item.vue b/pages/goods/components/comment-item.vue new file mode 100644 index 0000000..cee703d --- /dev/null +++ b/pages/goods/components/comment-item.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/pages/goods/components/filter-bar.vue b/pages/goods/components/filter-bar.vue new file mode 100644 index 0000000..1b7bbd7 --- /dev/null +++ b/pages/goods/components/filter-bar.vue @@ -0,0 +1,350 @@ + + + + + diff --git a/pages/goods/components/goods-comment.vue b/pages/goods/components/goods-comment.vue new file mode 100644 index 0000000..2316d97 --- /dev/null +++ b/pages/goods/components/goods-comment.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/pages/goods/components/goods-detail.vue b/pages/goods/components/goods-detail.vue new file mode 100644 index 0000000..e98977b --- /dev/null +++ b/pages/goods/components/goods-detail.vue @@ -0,0 +1,36 @@ + + + + + diff --git a/pages/goods/components/goods-info.vue b/pages/goods/components/goods-info.vue new file mode 100644 index 0000000..01bcc35 --- /dev/null +++ b/pages/goods/components/goods-info.vue @@ -0,0 +1,158 @@ + + + + + diff --git a/pages/goods/detail.vue b/pages/goods/detail.vue new file mode 100644 index 0000000..d2bdcf1 --- /dev/null +++ b/pages/goods/detail.vue @@ -0,0 +1,250 @@ + + + + + diff --git a/pages/goods/list.vue b/pages/goods/list.vue new file mode 100644 index 0000000..8d0dd16 --- /dev/null +++ b/pages/goods/list.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/pages/goods/search.vue b/pages/goods/search.vue new file mode 100644 index 0000000..c697192 --- /dev/null +++ b/pages/goods/search.vue @@ -0,0 +1,164 @@ + + + + + diff --git a/pages/index/category.vue b/pages/index/category.vue new file mode 100644 index 0000000..02f2891 --- /dev/null +++ b/pages/index/category.vue @@ -0,0 +1,243 @@ + + + + + diff --git a/pages/index/components/banner.vue b/pages/index/components/banner.vue new file mode 100644 index 0000000..601eb71 --- /dev/null +++ b/pages/index/components/banner.vue @@ -0,0 +1,57 @@ + + + + + diff --git a/pages/index/components/coupon-activity.vue b/pages/index/components/coupon-activity.vue new file mode 100644 index 0000000..20e3ec8 --- /dev/null +++ b/pages/index/components/coupon-activity.vue @@ -0,0 +1,179 @@ + + + + + diff --git a/pages/index/components/hot-category.vue b/pages/index/components/hot-category.vue new file mode 100644 index 0000000..02a1d0f --- /dev/null +++ b/pages/index/components/hot-category.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/pages/index/components/tabbar.vue b/pages/index/components/tabbar.vue new file mode 100644 index 0000000..48be5cc --- /dev/null +++ b/pages/index/components/tabbar.vue @@ -0,0 +1,146 @@ + + + + + diff --git a/pages/index/home.vue b/pages/index/home.vue new file mode 100644 index 0000000..94d7ff2 --- /dev/null +++ b/pages/index/home.vue @@ -0,0 +1,147 @@ + + + + + diff --git a/pages/index/my.vue b/pages/index/my.vue new file mode 100644 index 0000000..d871cc2 --- /dev/null +++ b/pages/index/my.vue @@ -0,0 +1,298 @@ + + + + + diff --git a/pages/index/shopping-cart.vue b/pages/index/shopping-cart.vue new file mode 100644 index 0000000..d454e21 --- /dev/null +++ b/pages/index/shopping-cart.vue @@ -0,0 +1,239 @@ + + + + + diff --git a/pages/market/coupon.vue b/pages/market/coupon.vue new file mode 100644 index 0000000..5596a14 --- /dev/null +++ b/pages/market/coupon.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/pages/order/comment.vue b/pages/order/comment.vue new file mode 100644 index 0000000..7d99e33 --- /dev/null +++ b/pages/order/comment.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/pages/order/components/cancel.vue b/pages/order/components/cancel.vue new file mode 100644 index 0000000..6501161 --- /dev/null +++ b/pages/order/components/cancel.vue @@ -0,0 +1,113 @@ + + + + + diff --git a/pages/order/components/comment.vue b/pages/order/components/comment.vue new file mode 100644 index 0000000..86ee711 --- /dev/null +++ b/pages/order/components/comment.vue @@ -0,0 +1,121 @@ + + + + + diff --git a/pages/order/components/op-btns.vue b/pages/order/components/op-btns.vue new file mode 100644 index 0000000..3d25e4a --- /dev/null +++ b/pages/order/components/op-btns.vue @@ -0,0 +1,41 @@ + + + diff --git a/pages/order/components/op.vue b/pages/order/components/op.vue new file mode 100644 index 0000000..b0a47ce --- /dev/null +++ b/pages/order/components/op.vue @@ -0,0 +1,80 @@ + + + diff --git a/pages/order/components/pay.vue b/pages/order/components/pay.vue new file mode 100644 index 0000000..b718469 --- /dev/null +++ b/pages/order/components/pay.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/pages/order/components/status-tag.vue b/pages/order/components/status-tag.vue new file mode 100644 index 0000000..a0406a0 --- /dev/null +++ b/pages/order/components/status-tag.vue @@ -0,0 +1,23 @@ + + + diff --git a/pages/order/detail.vue b/pages/order/detail.vue new file mode 100644 index 0000000..e4e3591 --- /dev/null +++ b/pages/order/detail.vue @@ -0,0 +1,231 @@ + + + + + diff --git a/pages/order/dict/index.ts b/pages/order/dict/index.ts new file mode 100644 index 0000000..1311c2c --- /dev/null +++ b/pages/order/dict/index.ts @@ -0,0 +1,92 @@ +export const OrderStatus = [ + { + label: "待付款", + desc: "等待用户付款", + value: 0, + color: "info", + icon: "shop-icon-order-paid", + }, + { + label: "待发货", + desc: "等待商家发货", + value: 1, + icon: "shop-icon-order-not-shipped", + }, + { + label: "待收货", + desc: "等待用户收货", + value: 2, + icon: "shop-icon-order-received", + }, + { + label: "待评价", + desc: "等待用户评价", + value: 3, + icon: "shop-icon-order-comment", + }, + { + label: "已完成", + desc: "完成", + value: 4, + color: "success", + icon: "shop-icon-order-success", + }, + { + label: "退款中", + desc: "后台退款中", + value: 5, + color: "error", + icon: "shop-icon-order-refund", + }, + { + label: "已退款", + desc: "订单已退款", + value: 6, + color: "warning", + icon: "shop-icon-order-refund", + }, + { + label: "已关闭", + desc: "订单已关闭", + value: 7, + color: "info", + icon: "shop-icon-order-close", + }, +]; + +export const PayType = [ + { + label: "未支付", + value: 0, + }, + { + label: "微信", + value: 1, + key: "wxpay", + icon: "/static/icon/wxpay.png", + }, + { + label: "支付宝", + value: 2, + key: "alipay", + icon: "/static/icon/alipay.png", + }, +]; + +export const RefundStatus = [ + { + label: "申请中", + value: 0, + color: "warning", + }, + { + label: "已退款", + value: 1, + color: "success", + }, + { + label: "拒绝退款", + value: 2, + color: "error", + }, +]; diff --git a/pages/order/list.vue b/pages/order/list.vue new file mode 100644 index 0000000..81bfd6c --- /dev/null +++ b/pages/order/list.vue @@ -0,0 +1,240 @@ + + + + + diff --git a/pages/order/logistics.vue b/pages/order/logistics.vue new file mode 100644 index 0000000..60117c6 --- /dev/null +++ b/pages/order/logistics.vue @@ -0,0 +1,108 @@ + + + + + diff --git a/pages/order/refund.vue b/pages/order/refund.vue new file mode 100644 index 0000000..dbcbffd --- /dev/null +++ b/pages/order/refund.vue @@ -0,0 +1,126 @@ + + + + + diff --git a/pages/order/submit.vue b/pages/order/submit.vue new file mode 100644 index 0000000..33e56a8 --- /dev/null +++ b/pages/order/submit.vue @@ -0,0 +1,209 @@ + + + + + diff --git a/pages/user/about.vue b/pages/user/about.vue new file mode 100644 index 0000000..db93eb9 --- /dev/null +++ b/pages/user/about.vue @@ -0,0 +1,57 @@ + + + + + diff --git a/pages/user/address-edit.vue b/pages/user/address-edit.vue new file mode 100644 index 0000000..9d919b0 --- /dev/null +++ b/pages/user/address-edit.vue @@ -0,0 +1,151 @@ + + + + + diff --git a/pages/user/address-list.vue b/pages/user/address-list.vue new file mode 100644 index 0000000..794a413 --- /dev/null +++ b/pages/user/address-list.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/pages/user/captcha.vue b/pages/user/captcha.vue new file mode 100644 index 0000000..112924e --- /dev/null +++ b/pages/user/captcha.vue @@ -0,0 +1,132 @@ + + + + + diff --git a/pages/user/doc.vue b/pages/user/doc.vue new file mode 100644 index 0000000..1bc5b51 --- /dev/null +++ b/pages/user/doc.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/pages/user/edit.vue b/pages/user/edit.vue new file mode 100644 index 0000000..a8b7b6d --- /dev/null +++ b/pages/user/edit.vue @@ -0,0 +1,67 @@ + + + + + diff --git a/pages/user/login.vue b/pages/user/login.vue new file mode 100644 index 0000000..acecfd9 --- /dev/null +++ b/pages/user/login.vue @@ -0,0 +1,473 @@ + + + + + diff --git a/pages/user/set.vue b/pages/user/set.vue new file mode 100644 index 0000000..6e09f09 --- /dev/null +++ b/pages/user/set.vue @@ -0,0 +1,154 @@ + + + + + diff --git a/pages/user/static/icon/apple.png b/pages/user/static/icon/apple.png new file mode 100644 index 0000000..2d0586e Binary files /dev/null and b/pages/user/static/icon/apple.png differ diff --git a/pages/user/static/icon/phone.png b/pages/user/static/icon/phone.png new file mode 100644 index 0000000..fae242b Binary files /dev/null and b/pages/user/static/icon/phone.png differ diff --git a/pages/user/static/icon/wx.png b/pages/user/static/icon/wx.png new file mode 100644 index 0000000..edd8c90 Binary files /dev/null and b/pages/user/static/icon/wx.png differ diff --git a/router/index.ts b/router/index.ts new file mode 100644 index 0000000..4eb98c4 --- /dev/null +++ b/router/index.ts @@ -0,0 +1,27 @@ +import { router, useStore } from "/@/cool"; + +const ignoreToken = [ + "/pages/index/home", + "/pages/index/category", + "/pages/index/shopping-cart", + "/pages/goods/detail", + "/pages/goods/search", + "/pages/goods/list", + "/pages/user/login", + "/pages/user/captcha", + "/pages/user/doc", +]; + +router.beforeEach((to, next) => { + const { user } = useStore(); + + if (ignoreToken.includes(to.path) || to.path.startsWith("/pages/demo")) { + next(); + } else { + if (user.token) { + next(); + } else { + router.login(); + } + } +}); diff --git a/service/test.ts b/service/test.ts new file mode 100644 index 0000000..5b6aa7b --- /dev/null +++ b/service/test.ts @@ -0,0 +1,6 @@ +import { BaseService, Service } from "/@/cool"; + +@Service("test") +class Test extends BaseService {} + +export default Test; diff --git a/static/css/common.scss b/static/css/common.scss new file mode 100644 index 0000000..1bc6bbb --- /dev/null +++ b/static/css/common.scss @@ -0,0 +1,47 @@ +.cl-button { + &.is-custom { + height: 80rpx; + font-size: 30rpx; + width: 100%; + } +} + +.cl-empty { + &__icon { + height: 300rpx; + } +} + +.card { + background-color: #ffffff; + padding: 14rpx 24rpx; + margin-bottom: 24rpx; + border-radius: 24rpx; + + .label { + display: flex; + align-items: center; + font-size: 28rpx; + line-height: 1; + font-weight: 500; + padding: 10rpx 0 14rpx 0; + } + + :deep(.cl-list-item) { + .cl-list-item__label { + font-size: 26rpx; + } + + .cl-list-item__container { + padding: 0; + } + + .cl-list-item__content { + min-height: auto; + } + } + + &:last-child { + margin-bottom: 0; + } +} diff --git a/static/css/iconfont/font.ttf b/static/css/iconfont/font.ttf new file mode 100644 index 0000000..0d5b620 Binary files /dev/null and b/static/css/iconfont/font.ttf differ diff --git a/static/css/iconfont/font.woff b/static/css/iconfont/font.woff new file mode 100644 index 0000000..0ee4622 Binary files /dev/null and b/static/css/iconfont/font.woff differ diff --git a/static/css/iconfont/font.woff2 b/static/css/iconfont/font.woff2 new file mode 100644 index 0000000..fe43698 Binary files /dev/null and b/static/css/iconfont/font.woff2 differ diff --git a/static/css/iconfont/index.scss b/static/css/iconfont/index.scss new file mode 100644 index 0000000..dc00689 --- /dev/null +++ b/static/css/iconfont/index.scss @@ -0,0 +1,134 @@ +@font-face { + font-family: "shop-iconfont"; /* Project id 1805670 */ + src: + url("font.woff2") format("woff2"), + url("font.woff") format("woff"), + url("font.ttf") format("truetype"); +} + +[class*="shop-icon-"] { + font-family: "shop-iconfont"; + font-size: inherit; + font-style: normal; + line-height: 1; +} + +.shop-icon-list:before { + content: "\ec87"; +} + +.shop-icon-list2:before { + content: "\ec88"; +} + +.shop-icon-order-close:before { + content: "\ec86"; +} + +.shop-icon-order-success:before { + content: "\ec85"; +} + +.shop-icon-order-comment:before { + content: "\ec7b"; +} + +.shop-icon-order-received:before { + content: "\ec7d"; +} + +.shop-icon-order-paid:before { + content: "\ec7e"; +} + +.shop-icon-order-not-shipped:before { + content: "\ec7f"; +} + +.shop-icon-order-refund:before { + content: "\ec80"; +} + +.shop-icon-order-received2:before { + content: "\ec81"; +} + +.shop-icon-zoom:before { + content: "\ec82"; +} + +.shop-icon-sku:before { + content: "\e762"; +} + +.shop-icon-set:before { + content: "\e761"; +} + +.shop-icon-home:before { + content: "\ec7a"; +} + +.shop-icon-shopping-cart:before { + content: "\ec79"; +} + +.shop-icon-more:before { + content: "\e657"; +} + +.shop-icon-q-order:before { + content: "\e697"; +} + +.shop-icon-q-pay:before { + content: "\e698"; +} + +.shop-icon-q-refund:before { + content: "\e699"; +} + +.shop-icon-q-logistics:before { + content: "\e69a"; +} + +.shop-icon-setting:before { + content: "\e68b"; +} + +.shop-icon-coupon:before { + content: "\e68c"; +} + +.shop-icon-order:before { + content: "\e68d"; +} + +.shop-icon-location:before { + content: "\e68e"; +} + +.shop-icon-filter:before { + content: "\e68f"; +} + +.shop-icon-message:before { + content: "\e691"; +} + +.shop-icon-delete:before { + content: "\e693"; +} + +.shop-icon-sort:before { + content: "\e694"; +} + +.shop-icon-search:before { + content: "\e695"; +} + +.shop-icon-custom:before { + content: "\e696"; +} diff --git a/static/css/index.scss b/static/css/index.scss new file mode 100644 index 0000000..4d82f70 --- /dev/null +++ b/static/css/index.scss @@ -0,0 +1,43 @@ +/* #ifdef H5 */ +* { + font-family: Arial, "Microsoft Yahei", "微软雅黑"; +} + +.uni-page-head-btn { + display: inline-flex; + align-items: center; +} +/* #endif */ + +// 主题 +.cl-page { + &.theme-default { + // 渐变色 + .cl-tag.cl-tag--primary:not(.is-plain), + .cl-button--primary:not(.is-plain) { + background: linear-gradient(120deg, rgba($cl-color-primary, 0.7), $cl-color-primary); + border: 0; + } + } +} + +// 其他 +.flex1 { + flex: 1; +} + +.mp-html { + img, + image { + display: block; + max-width: 100%; + } + + /* #ifndef MP */ + * { + margin: revert !important; + } + /* #endif */ +} + +@import "./common.scss"; diff --git a/static/empty/address.png b/static/empty/address.png new file mode 100644 index 0000000..f5edebb Binary files /dev/null and b/static/empty/address.png differ diff --git a/static/empty/comm.png b/static/empty/comm.png new file mode 100644 index 0000000..2b72a95 Binary files /dev/null and b/static/empty/comm.png differ diff --git a/static/empty/coupon.png b/static/empty/coupon.png new file mode 100644 index 0000000..84471d3 Binary files /dev/null and b/static/empty/coupon.png differ diff --git a/static/empty/message.png b/static/empty/message.png new file mode 100644 index 0000000..09f8b9f Binary files /dev/null and b/static/empty/message.png differ diff --git a/static/empty/network.png b/static/empty/network.png new file mode 100644 index 0000000..8c7b637 Binary files /dev/null and b/static/empty/network.png differ diff --git a/static/empty/order.png b/static/empty/order.png new file mode 100644 index 0000000..5c30fc3 Binary files /dev/null and b/static/empty/order.png differ diff --git a/static/empty/spopping-cart.png b/static/empty/spopping-cart.png new file mode 100644 index 0000000..6d574f3 Binary files /dev/null and b/static/empty/spopping-cart.png differ diff --git a/static/icon/alipay.png b/static/icon/alipay.png new file mode 100644 index 0000000..7f5b22c Binary files /dev/null and b/static/icon/alipay.png differ diff --git a/static/icon/tabbar/category.png b/static/icon/tabbar/category.png new file mode 100644 index 0000000..309e9e6 Binary files /dev/null and b/static/icon/tabbar/category.png differ diff --git a/static/icon/tabbar/category2.png b/static/icon/tabbar/category2.png new file mode 100644 index 0000000..07c8606 Binary files /dev/null and b/static/icon/tabbar/category2.png differ diff --git a/static/icon/tabbar/home.png b/static/icon/tabbar/home.png new file mode 100644 index 0000000..ffc6ce3 Binary files /dev/null and b/static/icon/tabbar/home.png differ diff --git a/static/icon/tabbar/home2.png b/static/icon/tabbar/home2.png new file mode 100644 index 0000000..9959444 Binary files /dev/null and b/static/icon/tabbar/home2.png differ diff --git a/static/icon/tabbar/my.png b/static/icon/tabbar/my.png new file mode 100644 index 0000000..c2a4a75 Binary files /dev/null and b/static/icon/tabbar/my.png differ diff --git a/static/icon/tabbar/my2.png b/static/icon/tabbar/my2.png new file mode 100644 index 0000000..2c880a9 Binary files /dev/null and b/static/icon/tabbar/my2.png differ diff --git a/static/icon/tabbar/shopping-cart.png b/static/icon/tabbar/shopping-cart.png new file mode 100644 index 0000000..52cf657 Binary files /dev/null and b/static/icon/tabbar/shopping-cart.png differ diff --git a/static/icon/tabbar/shopping-cart2.png b/static/icon/tabbar/shopping-cart2.png new file mode 100644 index 0000000..ddfcbea Binary files /dev/null and b/static/icon/tabbar/shopping-cart2.png differ diff --git a/static/icon/wxpay.png b/static/icon/wxpay.png new file mode 100644 index 0000000..044be3c Binary files /dev/null and b/static/icon/wxpay.png differ diff --git a/static/logo.png b/static/logo.png new file mode 100644 index 0000000..587669e Binary files /dev/null and b/static/logo.png differ diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..9086324 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@vue/tsconfig/tsconfig.json", + "compilerOptions": { + "ignoreDeprecations": "5.0", + "verbatimModuleSyntax": true, + "experimentalDecorators": true, + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "allowJs": true, + "paths": { + "/@/*": ["./*"], + "/$/*": ["./uni_modules/*"] + }, + "lib": ["esnext", "dom"], + "types": ["@dcloudio/types"], + "outDir": "esbuild" + }, + "include": ["**/*.ts", "**/*.vue", "main.js", "types/*.d.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/types/env.d.ts b/types/env.d.ts new file mode 100644 index 0000000..0efc421 --- /dev/null +++ b/types/env.d.ts @@ -0,0 +1,15 @@ +/// +/// +/// +/// + +declare module "*.vue" { + import { DefineComponent } from "vue"; + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types + const component: DefineComponent<{}, {}, any>; + export default component; +} + +declare module "virtual:ctx"; +declare module "virtual:eps"; +declare module "@dcloudio/vite-plugin-uni"; diff --git a/types/shop.d.ts b/types/shop.d.ts new file mode 100644 index 0000000..fec2de3 --- /dev/null +++ b/types/shop.d.ts @@ -0,0 +1,36 @@ +declare interface OrderGoods { + id?: any; + count: number; + isComment?: number; + orderId?: number; + price?: any; + spec: Eps.GoodsSpecEntity; + goodsInfo: Eps.GoodsInfoEntity; + [key: string]: any; +} + +declare interface CouponInfo extends Eps.MarketCouponInfoEntity { + condition?: { + fullAmount: number; + }; +} + +declare interface OrderInfo extends Eps.OrderInfoEntity { + address?: Eps.UserAddressEntity; + discountSource?: { + type: number; + objectId: number; + info: CouponInfo; + }; + goodsList?: OrderGoods[]; + refund?: { + orderNum: string; + amount: number; + realAmount: number; + status: number; + applyTime: Date; + time: Date; + reason: string; + refuseReason: string; + }; +} diff --git a/uni.scss b/uni.scss new file mode 100644 index 0000000..31e990f --- /dev/null +++ b/uni.scss @@ -0,0 +1,77 @@ +/** + * 这里是uni-app内置的常用样式变量 + * + * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 + * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App + * + */ + +/** + * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 + * + * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 + */ + +/* 颜色变量 */ +@import "/$/cool-ui/theme.scss"; + +/* 行为相关颜色 */ +$uni-color-primary: #6b69f8; +$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: #ffffff; +$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: 24upx; +$uni-font-size-base: 28upx; +$uni-font-size-lg: 32upx; + +/* 图片尺寸 */ +$uni-img-size-sm: 40upx; +$uni-img-size-base: 52upx; +$uni-img-size-lg: 80upx; + +/* Border Radius */ +$uni-border-radius-sm: 4upx; +$uni-border-radius-base: 6upx; +$uni-border-radius-lg: 12upx; +$uni-border-radius-circle: 50%; + +/* 水平间距 */ +$uni-spacing-row-sm: 10px; +$uni-spacing-row-base: 20upx; +$uni-spacing-row-lg: 30upx; + +/* 垂直间距 */ +$uni-spacing-col-sm: 8upx; +$uni-spacing-col-base: 16upx; +$uni-spacing-col-lg: 24upx; + +/* 透明度 */ +$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 + +/* 文章场景相关 */ +$uni-color-title: #2c405a; // 文章标题颜色 +$uni-font-size-title: 40upx; +$uni-color-subtitle: #555555; // 二级标题颜色 +$uni-font-size-subtitle: 36upx; +$uni-color-paragraph: #3f536e; // 文章段落颜色 +$uni-font-size-paragraph: 30upx; diff --git a/uni_modules/cool-app/components/cl-version-about/cl-version-about.vue b/uni_modules/cool-app/components/cl-version-about/cl-version-about.vue new file mode 100644 index 0000000..c4c54a1 --- /dev/null +++ b/uni_modules/cool-app/components/cl-version-about/cl-version-about.vue @@ -0,0 +1,32 @@ + + + diff --git a/uni_modules/cool-app/components/cl-version-upgrade/cl-version-upgrade.vue b/uni_modules/cool-app/components/cl-version-upgrade/cl-version-upgrade.vue new file mode 100644 index 0000000..137a565 --- /dev/null +++ b/uni_modules/cool-app/components/cl-version-upgrade/cl-version-upgrade.vue @@ -0,0 +1,119 @@ + + + + + diff --git a/uni_modules/cool-app/config.ts b/uni_modules/cool-app/config.ts new file mode 100644 index 0000000..c6e38f9 --- /dev/null +++ b/uni_modules/cool-app/config.ts @@ -0,0 +1,14 @@ +import type { ModuleConfig } from "/@/cool"; + +export default (): ModuleConfig => { + return { + description: "APP应用管理模块:版本升级、意见反馈、投诉建议、套餐设置", + + // #ifdef APP + demo: { + label: "Version 版本升级", + path: "/uni_modules/cool-app/pages/version/demo", + }, + // #endif + }; +}; diff --git a/uni_modules/cool-app/hooks/cache.ts b/uni_modules/cool-app/hooks/cache.ts new file mode 100644 index 0000000..0cfe626 --- /dev/null +++ b/uni_modules/cool-app/hooks/cache.ts @@ -0,0 +1,46 @@ +import { onShow } from "@dcloudio/uni-app"; +import { defineStore } from "pinia"; +import { ref } from "vue"; + +// 缓存 +export const useCache = defineStore("app.cache", () => { + // 缓存大小 + const size = ref("0KB"); + + // 获取缓存 + function get() { + // #ifdef APP + // @ts-ignore + plus.cache.calculate(function (s: number) { + //size是多少个字节单位是b + if (s < 1024) { + size.value = s + "B"; + } else if (s / 1024 >= 1 && s / 1024 / 1024 < 1) { + size.value = Math.floor((s / 1024) * 100) / 100 + "KB"; + } else if (s / 1024 / 1024 >= 1) { + size.value = Math.floor((s / 1024 / 1024) * 100) / 100 + "M"; + } + }); + // #endif + } + + // 清空缓存 + function clear() { + // #ifdef APP + // @ts-ignore + plus.cache.clear(function () { + get(); + }); + // #endif + } + + onShow(() => { + get(); + }); + + return { + size, + get, + clear, + }; +}); diff --git a/uni_modules/cool-app/hooks/index.ts b/uni_modules/cool-app/hooks/index.ts new file mode 100644 index 0000000..eb96e32 --- /dev/null +++ b/uni_modules/cool-app/hooks/index.ts @@ -0,0 +1,2 @@ +export * from "./version"; +export * from "./cache"; diff --git a/uni_modules/cool-app/hooks/version.ts b/uni_modules/cool-app/hooks/version.ts new file mode 100644 index 0000000..1ddb53f --- /dev/null +++ b/uni_modules/cool-app/hooks/version.ts @@ -0,0 +1,171 @@ +import { defineStore } from "pinia"; +import { ref } from "vue"; +import { service } from "/@/cool"; +import { useUi } from "/$/cool-ui"; +import { compareVersions, getVersion } from "../utils"; +import { isAndroid } from "/@/cool/utils"; + +// 版本信息 +export function useVersion() { + const ui = useUi(); + + const store = defineStore("app.version", () => { + // 版本号 + const num = ref(); + + // 是否能升级 + const isUpgrade = ref(false); + + // 检测状态 + const loading = ref(false); + + // 下载进度 + const progress = ref(); + + // 新版本信息 + const updateInfo = ref(); + + let req: any; + let task: UniApp.DownloadTask | null; + + // 检测更新 + async function check() { + // #ifdef APP + loading.value = true; + + await req; + + await service.app.version + .check({ + version: num.value, + type: isAndroid ? 0 : 1, + }) + .then((res) => { + if (res) { + console.log("[cool-app] 新版本信息", res); + updateInfo.value = res; + isUpgrade.value = compareVersions(res?.version, num.value) === 1; + } + }) + .catch((err) => { + ui.showToast(err.message); + }); + + loading.value = false; + // #endif + } + + // 更新资源包 + function update(isConfirm: boolean = true, cb?: () => void) { + const { url, forceUpdate, version, description, hotUpdate } = updateInfo.value || {}; + + function next() { + if (!isUpgrade.value) { + return false; + } + + if (!updateInfo.value) { + return ui.showToast("未检测到版本信息"); + } + + if (!url) { + return ui.showToast(hotUpdate ? "资源包错误" : "APP下载地址错误"); + } + + if (hotUpdate) { + ui.showLoading({ + text: "下载资源包", + border: true, + }); + + task = uni.downloadFile({ + url, + success(res) { + if (cb) { + cb(); + } + + ui.hideLoading(); + + if (res.statusCode == 200) { + plus.runtime.install( + res.tempFilePath, + { force: !!forceUpdate }, + () => { + num.value = version; + ui.showToast("更新成功,重启中"); + plus.runtime.restart(); + }, + ); + } else { + ui.showToast("下载资源包失败"); + } + }, + complete() { + ui.hideLoading(); + }, + }); + + task.onProgressUpdate((res) => { + progress.value = res.progress; + }); + } else { + plus.runtime.openURL(url); + } + } + + if (isUpgrade.value) { + if (isConfirm) { + ui.showConfirm({ + title: "检查到新版本", + message: description, + confirmButtonText: "立即更新", + callback(action) { + if (action == "confirm") { + next(); + } + }, + }); + } else { + next(); + } + } else { + ui.showToast("当前已是最新版本"); + } + } + + // 取消下载 + function cancel() { + task?.abort(); + } + + // 清空 + function clear() { + progress.value = 0; + } + + // 获取版本号 + function get() { + req = getVersion().then((res) => { + num.value = res; + }); + } + + get(); + + return { + num, + progress, + updateInfo, + isUpgrade, + loading, + check, + update, + get, + clear, + cancel, + }; + }); + + return store(); +} diff --git a/uni_modules/cool-app/index.ts b/uni_modules/cool-app/index.ts new file mode 100644 index 0000000..c2da53d --- /dev/null +++ b/uni_modules/cool-app/index.ts @@ -0,0 +1,2 @@ +export * from "./hooks"; +export * from "./utils"; diff --git a/uni_modules/cool-app/pages/complain/detail.vue b/uni_modules/cool-app/pages/complain/detail.vue new file mode 100644 index 0000000..faf6b6d --- /dev/null +++ b/uni_modules/cool-app/pages/complain/detail.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/uni_modules/cool-app/pages/complain/list.vue b/uni_modules/cool-app/pages/complain/list.vue new file mode 100644 index 0000000..69309de --- /dev/null +++ b/uni_modules/cool-app/pages/complain/list.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/uni_modules/cool-app/pages/complain/submit.vue b/uni_modules/cool-app/pages/complain/submit.vue new file mode 100644 index 0000000..38958e1 --- /dev/null +++ b/uni_modules/cool-app/pages/complain/submit.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/uni_modules/cool-app/pages/feedback/detail.vue b/uni_modules/cool-app/pages/feedback/detail.vue new file mode 100644 index 0000000..4a66266 --- /dev/null +++ b/uni_modules/cool-app/pages/feedback/detail.vue @@ -0,0 +1,91 @@ + + + + + diff --git a/uni_modules/cool-app/pages/feedback/list.vue b/uni_modules/cool-app/pages/feedback/list.vue new file mode 100644 index 0000000..8fbe46c --- /dev/null +++ b/uni_modules/cool-app/pages/feedback/list.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/uni_modules/cool-app/pages/feedback/submit.vue b/uni_modules/cool-app/pages/feedback/submit.vue new file mode 100644 index 0000000..948d431 --- /dev/null +++ b/uni_modules/cool-app/pages/feedback/submit.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/uni_modules/cool-app/pages/version/demo.vue b/uni_modules/cool-app/pages/version/demo.vue new file mode 100644 index 0000000..b25369f --- /dev/null +++ b/uni_modules/cool-app/pages/version/demo.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/uni_modules/cool-app/pages_init.json b/uni_modules/cool-app/pages_init.json new file mode 100644 index 0000000..33ca272 --- /dev/null +++ b/uni_modules/cool-app/pages_init.json @@ -0,0 +1,51 @@ +{ + "subPackages": [ + { + "root": "uni_modules/cool-app/pages", + "pages": [ + { + "path": "version/demo", + "style": { + "navigationBarTitleText": "版本升级" + } + }, + { + "path": "complain/detail", + "style": { + "navigationBarTitleText": "投诉详情" + } + }, + { + "path": "complain/list", + "style": { + "navigationBarTitleText": "投诉列表" + } + }, + { + "path": "complain/submit", + "style": { + "navigationStyle": "custom" + } + }, + { + "path": "feedback/detail", + "style": { + "navigationBarTitleText": "反馈详情" + } + }, + { + "path": "feedback/list", + "style": { + "navigationBarTitleText": "反馈列表" + } + }, + { + "path": "feedback/submit", + "style": { + "navigationStyle": "custom" + } + } + ] + } + ] +} diff --git a/uni_modules/cool-app/static/bg.png b/uni_modules/cool-app/static/bg.png new file mode 100644 index 0000000..bf114e0 Binary files /dev/null and b/uni_modules/cool-app/static/bg.png differ diff --git a/uni_modules/cool-app/utils/index.ts b/uni_modules/cool-app/utils/index.ts new file mode 100644 index 0000000..ab9ba3e --- /dev/null +++ b/uni_modules/cool-app/utils/index.ts @@ -0,0 +1,97 @@ +import { isAndroid, uuid } from "/@/cool/utils"; + +// 版本比较 +export function compareVersions(v1: string, v2: string) { + const arr1 = v1.split(".").map(Number); + const arr2 = v2.split(".").map(Number); + const maxLength = Math.max(arr1.length, arr2.length); + + for (let i = 0; i < maxLength; i++) { + const num1 = arr1[i] || 0; + const num2 = arr2[i] || 0; + + if (num1 > num2) return 1; + if (num2 > num1) return -1; + } + + return 0; +} + +// 获取版本号 +export function getVersion(): Promise { + return new Promise((resolve) => { + // #ifdef APP + const packVersion: any = plus.runtime.version; + const appid: any = plus.runtime.appid; + plus.runtime.getProperty(appid, function (widgetInfo) { + resolve( + String(packVersion) > String(widgetInfo.version) ? packVersion : widgetInfo.version, + ); + }); + // #endif + + // #ifndef APP + resolve("1.0.0"); + // #endif + }); +} + +// 获取 deviceId +export function getDeviceId(): string { + // #ifdef APP + return plus.device.uuid!; + // #endif + + // #ifndef APP + return uuid(); + // #endif +} + +// 获取 oaid +export function getOAID() { + return new Promise((resolve) => { + plus.device.getOAID({ + success(res) { + resolve(res.oaid); + }, + fail() { + resolve(0); + }, + }); + }); +} + +// 获取 androidId +export function getAndroidId() { + if (isAndroid) { + const Settings = plus.android.importClass("android.provider.Settings"); + const main = plus.android.runtimeMainActivity(); + // @ts-ignore + return Settings.Secure.getString(main.getContentResolver(), Settings.Secure.ANDROID_ID); + } +} + +// 获取 mac +export function getMac() { + if (isAndroid) { + const net = plus.android.importClass("java.net.NetworkInterface"); + // @ts-ignore + const wl0 = net.getByName("wlan0"); + const macByte = wl0.getHardwareAddress(); + let str = ""; + for (let i = 0; i < macByte.length; i++) { + let tmp = ""; + let num = macByte[i]; + if (num < 0) { + tmp = (255 + num + 1).toString(16); + } else { + tmp = num.toString(16); + } + if (tmp.length == 1) { + tmp = "0" + tmp; + } + str += tmp; + } + return str; + } +} diff --git a/uni_modules/cool-cs/components/msg-item.vue b/uni_modules/cool-cs/components/msg-item.vue new file mode 100644 index 0000000..788c57e --- /dev/null +++ b/uni_modules/cool-cs/components/msg-item.vue @@ -0,0 +1,187 @@ + + + + + diff --git a/uni_modules/cool-cs/components/msg-list.vue b/uni_modules/cool-cs/components/msg-list.vue new file mode 100644 index 0000000..13f0739 --- /dev/null +++ b/uni_modules/cool-cs/components/msg-list.vue @@ -0,0 +1,132 @@ + + + + + diff --git a/uni_modules/cool-cs/components/tools/emoji.vue b/uni_modules/cool-cs/components/tools/emoji.vue new file mode 100644 index 0000000..4ad9a51 --- /dev/null +++ b/uni_modules/cool-cs/components/tools/emoji.vue @@ -0,0 +1,142 @@ + + + + + diff --git a/uni_modules/cool-cs/components/tools/fn.vue b/uni_modules/cool-cs/components/tools/fn.vue new file mode 100644 index 0000000..81c9e2e --- /dev/null +++ b/uni_modules/cool-cs/components/tools/fn.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/uni_modules/cool-cs/components/tools/index.vue b/uni_modules/cool-cs/components/tools/index.vue new file mode 100644 index 0000000..9f834a8 --- /dev/null +++ b/uni_modules/cool-cs/components/tools/index.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/uni_modules/cool-cs/config.ts b/uni_modules/cool-cs/config.ts new file mode 100644 index 0000000..7934d87 --- /dev/null +++ b/uni_modules/cool-cs/config.ts @@ -0,0 +1,14 @@ +import { config, type ModuleConfig } from "/@/cool"; + +export default (): ModuleConfig => { + return { + description: "客服聊天模块", + options: { + url: config.host + "/cs", + }, + demo: { + label: "CS 客服聊天", + path: "/uni_modules/cool-cs/pages/chat", + }, + }; +}; diff --git a/uni_modules/cool-cs/hooks/index.ts b/uni_modules/cool-cs/hooks/index.ts new file mode 100644 index 0000000..54134f4 --- /dev/null +++ b/uni_modules/cool-cs/hooks/index.ts @@ -0,0 +1,4 @@ +export * from "./tools"; +export * from "./socket"; +export * from "./session"; +export * from "./message"; diff --git a/uni_modules/cool-cs/hooks/message.ts b/uni_modules/cool-cs/hooks/message.ts new file mode 100644 index 0000000..da9fa2a --- /dev/null +++ b/uni_modules/cool-cs/hooks/message.ts @@ -0,0 +1,120 @@ +import { defineStore } from "pinia"; +import { computed, ref } from "vue"; +import type { Cs } from "../types"; +import dayjs from "dayjs"; +import { service, useStore } from "/@/cool"; +import { last } from "lodash-es"; +import { useSession } from "./session"; +import { uuid } from "/@/cool/utils"; +import { useScroller } from "./tools"; +import { dateFormatter } from "../utils"; + +export const useMessage = defineStore("cs.message", () => { + const session = useSession(); + const scroller = useScroller(); + const { user } = useStore(); + + // 加载中 + const loading = ref(false); + + // 所有页 + const data = ref<{ id: string; data: Cs.Msg[] }[]>([]); + + // 列表 + const list = computed(() => { + data.value.forEach((e) => { + if (e.data[0]) { + let date = e.data[0].createTime; + + if (date) { + e.data.forEach((a, i) => { + const d = dateFormatter(a.createTime); + + if (i == 0) { + a.date = d; + } + + if (dayjs(a.createTime).subtract(10, "minute").isAfter(dayjs(date))) { + a.date = d; + date = a.createTime; + } + }); + } + } + }); + + return data.value; + }); + + // 追加消息 + function append(item: Cs.Msg) { + const list = last(data.value)?.data; + + if (list) { + list.push({ + sessionId: session.info?.id, + type: 0, + nickName: user.info?.nickName, + avatarUrl: user.info?.avatarUrl, + ...item, + isAnimation: true, + }); + + scroller.scrollToBottom(); + } + } + + // 清除消息 + function clear() { + data.value = []; + } + + // 读消息 + function read(id: number) { + service.cs.msg.read({ + msgIds: [id], + }); + } + + // 获取消息 + async function refresh(params?: any) { + loading.value = true; + + if (params.page == 1) { + data.value = []; + } + + await service.cs.msg + .page({ + sessionId: session.info?.id, + order: "createTime", + sort: "desc", + ...params, + }) + .then((res) => { + res.list.forEach((e) => { + if (e.type == 1) { + e.avatarUrl = e.adminUserHeadImg; + e.nickName = e.adminUserName; + } + }); + + data.value.unshift({ + id: uuid(), + data: res.list.reverse() as any[], + }); + }); + + loading.value = false; + } + + return { + data, + list, + loading, + append, + clear, + read, + refresh, + }; +}); diff --git a/uni_modules/cool-cs/hooks/session.ts b/uni_modules/cool-cs/hooks/session.ts new file mode 100644 index 0000000..f221f29 --- /dev/null +++ b/uni_modules/cool-cs/hooks/session.ts @@ -0,0 +1,24 @@ +import { defineStore } from "pinia"; +import { ref } from "vue"; +import type { Cs } from "../types"; + +export const useSession = defineStore("cs.session", () => { + // 详情 + const info = ref(); + + // 设置会话 + function set(data: Cs.Session) { + info.value = data; + } + + // 清除会话 + function clear() { + info.value = undefined; + } + + return { + info, + set, + clear, + }; +}); diff --git a/uni_modules/cool-cs/hooks/socket.ts b/uni_modules/cool-cs/hooks/socket.ts new file mode 100644 index 0000000..03324f0 --- /dev/null +++ b/uni_modules/cool-cs/hooks/socket.ts @@ -0,0 +1,96 @@ +import { defineStore } from "pinia"; +// @ts-ignore +import io, { type Socket } from "@hyoga/uni-socket.io"; +import type { Cs } from "../types"; +import { useStore, module } from "/@/cool"; +import { useSession } from "./session"; +import { useMessage } from "./message"; + +export const useSocket = defineStore("cs.socket", () => { + const config = module.config("cool-cs"); + const { user } = useStore(); + const session = useSession(); + const message = useMessage(); + + let client = undefined as Socket | undefined; + + // 连接 + function connect() { + if (!user.token) { + return false; + } + + if (client) { + disconnect(); + } + + if (!client) { + client = io(config.url, { + transports: ["websocket", "polling"], + auth: { + isAdmin: false, + token: user.token, + }, + }); + + client.on("connect", () => { + console.log("[cs] connect"); + }); + + client.on("disconnect", () => { + console.log("[cs] disconnect"); + }); + + client.on("msg", (data: Cs.Msg) => { + if (data.type == 1) { + if (data.sessionId == session.info?.id) { + // 追加消息 + message.append({ + ...data.user, + ...data, + isAnimation: true, + }); + + // 读消息 + message.read(data.id!); + } + } + }); + } + } + + // 断开连接 + function disconnect() { + client?.disconnect(); + client = undefined; + } + + // 发送消息 + function send(content: Cs.Content) { + if (client) { + // 发送事件 + client.emit("send", { + sessionId: session.info?.id, + content, + }); + + // 追加消息 + message.append({ content }); + } else { + console.log("[cs] client error"); + } + } + + // 监听退出 + uni.$on("user.logout", () => { + session.clear(); + message.clear(); + disconnect(); + }); + + return { + connect, + client, + send, + }; +}); diff --git a/uni_modules/cool-cs/hooks/tools.ts b/uni_modules/cool-cs/hooks/tools.ts new file mode 100644 index 0000000..bc06901 --- /dev/null +++ b/uni_modules/cool-cs/hooks/tools.ts @@ -0,0 +1,61 @@ +import { defineStore } from "pinia"; +import { nextTick, ref } from "vue"; +import { throttle } from "lodash-es"; + +export const useTools = defineStore("cs.tools", () => { + const visible = ref(false); + const mode = ref(""); + + // 打开 + function open(m: string) { + if (visible.value && mode.value === m) { + return close(); + } + + visible.value = true; + mode.value = m; + } + + // 关闭 + function close() { + visible.value = false; + } + + return { + visible, + mode, + open, + close, + }; +}); + +export const useScroller = defineStore("cs.scroller", () => { + // 滚动距离 + const top = ref(0); + + // 滚动动画 + const animation = ref(true); + + let n = 0; + + // 滚动到指定位置 + const scrollTo = throttle((scrollTop: number, smooth: boolean = true) => { + nextTick().then(() => { + top.value = scrollTop; + + animation.value = smooth; + }); + }, 500); + + // 滚动到底部 + const scrollToBottom = (smooth?: boolean) => { + scrollTo(100000 + n++, smooth); + }; + + return { + animation, + top, + scrollToBottom, + scrollTo, + }; +}); diff --git a/uni_modules/cool-cs/pages/chat.vue b/uni_modules/cool-cs/pages/chat.vue new file mode 100644 index 0000000..bb2780a --- /dev/null +++ b/uni_modules/cool-cs/pages/chat.vue @@ -0,0 +1,142 @@ + + + + + diff --git a/uni_modules/cool-cs/pages_init.json b/uni_modules/cool-cs/pages_init.json new file mode 100644 index 0000000..fccd4e3 --- /dev/null +++ b/uni_modules/cool-cs/pages_init.json @@ -0,0 +1,15 @@ +{ + "subPackages": [ + { + "root": "uni_modules/cool-cs/pages", + "pages": [ + { + "path": "chat", + "style": { + "navigationBarTitleText": "客服聊天" + } + } + ] + } + ] +} diff --git a/uni_modules/cool-cs/static/add.png b/uni_modules/cool-cs/static/add.png new file mode 100644 index 0000000..38acc2c Binary files /dev/null and b/uni_modules/cool-cs/static/add.png differ diff --git a/uni_modules/cool-cs/static/emoji.png b/uni_modules/cool-cs/static/emoji.png new file mode 100644 index 0000000..fb49e09 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji.png differ diff --git a/uni_modules/cool-cs/static/emoji/angry-face.png b/uni_modules/cool-cs/static/emoji/angry-face.png new file mode 100644 index 0000000..bd0b383 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/angry-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/anguished-face.png b/uni_modules/cool-cs/static/emoji/anguished-face.png new file mode 100644 index 0000000..fa4678b Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/anguished-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/astonished-face.png b/uni_modules/cool-cs/static/emoji/astonished-face.png new file mode 100644 index 0000000..41dc2b6 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/astonished-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/confounded-face.png b/uni_modules/cool-cs/static/emoji/confounded-face.png new file mode 100644 index 0000000..7e1b967 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/confounded-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/confused-face.png b/uni_modules/cool-cs/static/emoji/confused-face.png new file mode 100644 index 0000000..b01d70e Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/confused-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/crying-face.png b/uni_modules/cool-cs/static/emoji/crying-face.png new file mode 100644 index 0000000..c5aae1c Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/crying-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/disappointed-but-relieved-face.png b/uni_modules/cool-cs/static/emoji/disappointed-but-relieved-face.png new file mode 100644 index 0000000..f4f6e3e Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/disappointed-but-relieved-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/disappointed-face.png b/uni_modules/cool-cs/static/emoji/disappointed-face.png new file mode 100644 index 0000000..aa3e501 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/disappointed-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/dizzy-face.png b/uni_modules/cool-cs/static/emoji/dizzy-face.png new file mode 100644 index 0000000..9bd63d4 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/dizzy-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/drooling-face.png b/uni_modules/cool-cs/static/emoji/drooling-face.png new file mode 100644 index 0000000..a7e2545 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/drooling-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/expressionless-face.png b/uni_modules/cool-cs/static/emoji/expressionless-face.png new file mode 100644 index 0000000..a39bc99 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/expressionless-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-savouring-delicious-food.png b/uni_modules/cool-cs/static/emoji/face-savouring-delicious-food.png new file mode 100644 index 0000000..7f3d434 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-savouring-delicious-food.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-screaming-in-fear.png b/uni_modules/cool-cs/static/emoji/face-screaming-in-fear.png new file mode 100644 index 0000000..0458687 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-screaming-in-fear.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-throwing-a-kiss.png b/uni_modules/cool-cs/static/emoji/face-throwing-a-kiss.png new file mode 100644 index 0000000..15220bf Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-throwing-a-kiss.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-cold-sweat.png b/uni_modules/cool-cs/static/emoji/face-with-cold-sweat.png new file mode 100644 index 0000000..c91ab17 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-cold-sweat.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-cowboy-hat.png b/uni_modules/cool-cs/static/emoji/face-with-cowboy-hat.png new file mode 100644 index 0000000..5801afc Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-cowboy-hat.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-finger-covering-closed-lips.png b/uni_modules/cool-cs/static/emoji/face-with-finger-covering-closed-lips.png new file mode 100644 index 0000000..3e37c47 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-finger-covering-closed-lips.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-head-bandage.png b/uni_modules/cool-cs/static/emoji/face-with-head-bandage.png new file mode 100644 index 0000000..00471c0 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-head-bandage.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-look-of-triumph.png b/uni_modules/cool-cs/static/emoji/face-with-look-of-triumph.png new file mode 100644 index 0000000..fa3bb8e Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-look-of-triumph.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-medical-mask.png b/uni_modules/cool-cs/static/emoji/face-with-medical-mask.png new file mode 100644 index 0000000..8b237f5 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-medical-mask.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-monocle.png b/uni_modules/cool-cs/static/emoji/face-with-monocle.png new file mode 100644 index 0000000..12982a9 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-monocle.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-one-eyebrow-raised.png b/uni_modules/cool-cs/static/emoji/face-with-one-eyebrow-raised.png new file mode 100644 index 0000000..c14f913 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-one-eyebrow-raised.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-open-mouth-and-cold-sweat.png b/uni_modules/cool-cs/static/emoji/face-with-open-mouth-and-cold-sweat.png new file mode 100644 index 0000000..9359dd9 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-open-mouth-and-cold-sweat.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-open-mouth-vomiting.png b/uni_modules/cool-cs/static/emoji/face-with-open-mouth-vomiting.png new file mode 100644 index 0000000..637be5f Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-open-mouth-vomiting.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-open-mouth.png b/uni_modules/cool-cs/static/emoji/face-with-open-mouth.png new file mode 100644 index 0000000..6b9af1e Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-open-mouth.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-party-horn-and-party-hat.png b/uni_modules/cool-cs/static/emoji/face-with-party-horn-and-party-hat.png new file mode 100644 index 0000000..d1d3f27 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-party-horn-and-party-hat.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-pleading-eyes.png b/uni_modules/cool-cs/static/emoji/face-with-pleading-eyes.png new file mode 100644 index 0000000..3901299 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-pleading-eyes.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-rolling-eyes.png b/uni_modules/cool-cs/static/emoji/face-with-rolling-eyes.png new file mode 100644 index 0000000..3c1c933 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-rolling-eyes.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-stuck-out-tongue-and-tightly-closed-eyes.png b/uni_modules/cool-cs/static/emoji/face-with-stuck-out-tongue-and-tightly-closed-eyes.png new file mode 100644 index 0000000..13e5574 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-stuck-out-tongue-and-tightly-closed-eyes.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-stuck-out-tongue-and-winking-eye.png b/uni_modules/cool-cs/static/emoji/face-with-stuck-out-tongue-and-winking-eye.png new file mode 100644 index 0000000..3c6c276 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-stuck-out-tongue-and-winking-eye.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-stuck-out-tongue.png b/uni_modules/cool-cs/static/emoji/face-with-stuck-out-tongue.png new file mode 100644 index 0000000..9b040b3 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-stuck-out-tongue.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-thermometer.png b/uni_modules/cool-cs/static/emoji/face-with-thermometer.png new file mode 100644 index 0000000..407c0c8 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-thermometer.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-with-uneven-eyes-and-wavy-mouth.png b/uni_modules/cool-cs/static/emoji/face-with-uneven-eyes-and-wavy-mouth.png new file mode 100644 index 0000000..3777295 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-with-uneven-eyes-and-wavy-mouth.png differ diff --git a/uni_modules/cool-cs/static/emoji/face-without-mouth.png b/uni_modules/cool-cs/static/emoji/face-without-mouth.png new file mode 100644 index 0000000..8a2fbf3 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/face-without-mouth.png differ diff --git a/uni_modules/cool-cs/static/emoji/fearful-face.png b/uni_modules/cool-cs/static/emoji/fearful-face.png new file mode 100644 index 0000000..f1927f0 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/fearful-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/flushed-face.png b/uni_modules/cool-cs/static/emoji/flushed-face.png new file mode 100644 index 0000000..adad5ca Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/flushed-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/freezing-face.png b/uni_modules/cool-cs/static/emoji/freezing-face.png new file mode 100644 index 0000000..97a9310 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/freezing-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/frowning-face-with-open-mouth.png b/uni_modules/cool-cs/static/emoji/frowning-face-with-open-mouth.png new file mode 100644 index 0000000..1ec8ac6 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/frowning-face-with-open-mouth.png differ diff --git a/uni_modules/cool-cs/static/emoji/grimacing-face.png b/uni_modules/cool-cs/static/emoji/grimacing-face.png new file mode 100644 index 0000000..82ca911 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/grimacing-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/grinning-face-with-one-large-and-one-small-eye.png b/uni_modules/cool-cs/static/emoji/grinning-face-with-one-large-and-one-small-eye.png new file mode 100644 index 0000000..7f3ec34 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/grinning-face-with-one-large-and-one-small-eye.png differ diff --git a/uni_modules/cool-cs/static/emoji/grinning-face-with-smiling-eyes.png b/uni_modules/cool-cs/static/emoji/grinning-face-with-smiling-eyes.png new file mode 100644 index 0000000..d90a62d Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/grinning-face-with-smiling-eyes.png differ diff --git a/uni_modules/cool-cs/static/emoji/grinning-face-with-star-eyes.png b/uni_modules/cool-cs/static/emoji/grinning-face-with-star-eyes.png new file mode 100644 index 0000000..9d3a098 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/grinning-face-with-star-eyes.png differ diff --git a/uni_modules/cool-cs/static/emoji/grinning-face.png b/uni_modules/cool-cs/static/emoji/grinning-face.png new file mode 100644 index 0000000..56e7da7 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/grinning-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/hugging-face.png b/uni_modules/cool-cs/static/emoji/hugging-face.png new file mode 100644 index 0000000..edc9e01 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/hugging-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/hushed-face.png b/uni_modules/cool-cs/static/emoji/hushed-face.png new file mode 100644 index 0000000..f236530 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/hushed-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/imp.png b/uni_modules/cool-cs/static/emoji/imp.png new file mode 100644 index 0000000..7a4bcdb Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/imp.png differ diff --git a/uni_modules/cool-cs/static/emoji/kissing-face-with-closed-eyes.png b/uni_modules/cool-cs/static/emoji/kissing-face-with-closed-eyes.png new file mode 100644 index 0000000..a16080e Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/kissing-face-with-closed-eyes.png differ diff --git a/uni_modules/cool-cs/static/emoji/kissing-face-with-smiling-eyes.png b/uni_modules/cool-cs/static/emoji/kissing-face-with-smiling-eyes.png new file mode 100644 index 0000000..f041364 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/kissing-face-with-smiling-eyes.png differ diff --git a/uni_modules/cool-cs/static/emoji/kissing-face.png b/uni_modules/cool-cs/static/emoji/kissing-face.png new file mode 100644 index 0000000..7f57e24 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/kissing-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/loudly-crying-face.png b/uni_modules/cool-cs/static/emoji/loudly-crying-face.png new file mode 100644 index 0000000..37bc4fd Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/loudly-crying-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/lying-face.png b/uni_modules/cool-cs/static/emoji/lying-face.png new file mode 100644 index 0000000..a7af452 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/lying-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/money-mouth-face.png b/uni_modules/cool-cs/static/emoji/money-mouth-face.png new file mode 100644 index 0000000..e72b3b8 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/money-mouth-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/nauseated-face.png b/uni_modules/cool-cs/static/emoji/nauseated-face.png new file mode 100644 index 0000000..2b30261 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/nauseated-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/nerd-face.png b/uni_modules/cool-cs/static/emoji/nerd-face.png new file mode 100644 index 0000000..c915863 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/nerd-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/neutral-face.png b/uni_modules/cool-cs/static/emoji/neutral-face.png new file mode 100644 index 0000000..8fc3f3e Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/neutral-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/overheated-face.png b/uni_modules/cool-cs/static/emoji/overheated-face.png new file mode 100644 index 0000000..b8c9f63 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/overheated-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/pensive-face.png b/uni_modules/cool-cs/static/emoji/pensive-face.png new file mode 100644 index 0000000..1eefb52 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/pensive-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/persevering-face.png b/uni_modules/cool-cs/static/emoji/persevering-face.png new file mode 100644 index 0000000..daa2cc0 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/persevering-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/pouting-face.png b/uni_modules/cool-cs/static/emoji/pouting-face.png new file mode 100644 index 0000000..398f18a Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/pouting-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/relieved-face.png b/uni_modules/cool-cs/static/emoji/relieved-face.png new file mode 100644 index 0000000..502f517 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/relieved-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/rolling-on-the-floor-laughing.png b/uni_modules/cool-cs/static/emoji/rolling-on-the-floor-laughing.png new file mode 100644 index 0000000..2eabc38 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/rolling-on-the-floor-laughing.png differ diff --git a/uni_modules/cool-cs/static/emoji/serious-face-with-symbols-covering-mouth.png b/uni_modules/cool-cs/static/emoji/serious-face-with-symbols-covering-mouth.png new file mode 100644 index 0000000..c5c95e0 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/serious-face-with-symbols-covering-mouth.png differ diff --git a/uni_modules/cool-cs/static/emoji/shocked-face-with-exploding-head.png b/uni_modules/cool-cs/static/emoji/shocked-face-with-exploding-head.png new file mode 100644 index 0000000..c939400 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/shocked-face-with-exploding-head.png differ diff --git a/uni_modules/cool-cs/static/emoji/sleeping-face.png b/uni_modules/cool-cs/static/emoji/sleeping-face.png new file mode 100644 index 0000000..749e4ee Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/sleeping-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/sleepy-face.png b/uni_modules/cool-cs/static/emoji/sleepy-face.png new file mode 100644 index 0000000..21b72c1 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/sleepy-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/slightly-frowning-face.png b/uni_modules/cool-cs/static/emoji/slightly-frowning-face.png new file mode 100644 index 0000000..8608109 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/slightly-frowning-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/slightly-smiling-face.png b/uni_modules/cool-cs/static/emoji/slightly-smiling-face.png new file mode 100644 index 0000000..a0d68d1 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/slightly-smiling-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/smiling-face-with-halo.png b/uni_modules/cool-cs/static/emoji/smiling-face-with-halo.png new file mode 100644 index 0000000..0cd0b3d Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/smiling-face-with-halo.png differ diff --git a/uni_modules/cool-cs/static/emoji/smiling-face-with-heart-shaped-eyes.png b/uni_modules/cool-cs/static/emoji/smiling-face-with-heart-shaped-eyes.png new file mode 100644 index 0000000..2cefcb5 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/smiling-face-with-heart-shaped-eyes.png differ diff --git a/uni_modules/cool-cs/static/emoji/smiling-face-with-horns.png b/uni_modules/cool-cs/static/emoji/smiling-face-with-horns.png new file mode 100644 index 0000000..f0b56af Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/smiling-face-with-horns.png differ diff --git a/uni_modules/cool-cs/static/emoji/smiling-face-with-open-mouth-and-smiling-eyes.png b/uni_modules/cool-cs/static/emoji/smiling-face-with-open-mouth-and-smiling-eyes.png new file mode 100644 index 0000000..a702c93 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/smiling-face-with-open-mouth-and-smiling-eyes.png differ diff --git a/uni_modules/cool-cs/static/emoji/smiling-face-with-open-mouth-and-tightly-closed-eyes.png b/uni_modules/cool-cs/static/emoji/smiling-face-with-open-mouth-and-tightly-closed-eyes.png new file mode 100644 index 0000000..83ebaa5 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/smiling-face-with-open-mouth-and-tightly-closed-eyes.png differ diff --git a/uni_modules/cool-cs/static/emoji/smiling-face-with-open-mouth.png b/uni_modules/cool-cs/static/emoji/smiling-face-with-open-mouth.png new file mode 100644 index 0000000..7798b41 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/smiling-face-with-open-mouth.png differ diff --git a/uni_modules/cool-cs/static/emoji/smiling-face-with-smiling-eyes-and-hand-covering-mouth.png b/uni_modules/cool-cs/static/emoji/smiling-face-with-smiling-eyes-and-hand-covering-mouth.png new file mode 100644 index 0000000..27777df Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/smiling-face-with-smiling-eyes-and-hand-covering-mouth.png differ diff --git a/uni_modules/cool-cs/static/emoji/smiling-face-with-smiling-eyes-and-three-hearts.png b/uni_modules/cool-cs/static/emoji/smiling-face-with-smiling-eyes-and-three-hearts.png new file mode 100644 index 0000000..d621f0d Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/smiling-face-with-smiling-eyes-and-three-hearts.png differ diff --git a/uni_modules/cool-cs/static/emoji/smiling-face-with-smiling-eyes.png b/uni_modules/cool-cs/static/emoji/smiling-face-with-smiling-eyes.png new file mode 100644 index 0000000..69700dc Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/smiling-face-with-smiling-eyes.png differ diff --git a/uni_modules/cool-cs/static/emoji/smiling-face-with-sunglasses.png b/uni_modules/cool-cs/static/emoji/smiling-face-with-sunglasses.png new file mode 100644 index 0000000..2a70eff Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/smiling-face-with-sunglasses.png differ diff --git a/uni_modules/cool-cs/static/emoji/smirking-face.png b/uni_modules/cool-cs/static/emoji/smirking-face.png new file mode 100644 index 0000000..430d45b Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/smirking-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/sneezing-face.png b/uni_modules/cool-cs/static/emoji/sneezing-face.png new file mode 100644 index 0000000..18f5b95 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/sneezing-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/thinking-face.png b/uni_modules/cool-cs/static/emoji/thinking-face.png new file mode 100644 index 0000000..7431ed0 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/thinking-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/tired-face.png b/uni_modules/cool-cs/static/emoji/tired-face.png new file mode 100644 index 0000000..ff0898f Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/tired-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/upside-down-face.png b/uni_modules/cool-cs/static/emoji/upside-down-face.png new file mode 100644 index 0000000..677f746 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/upside-down-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/weary-face.png b/uni_modules/cool-cs/static/emoji/weary-face.png new file mode 100644 index 0000000..74325b9 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/weary-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/white-frowning-face.png b/uni_modules/cool-cs/static/emoji/white-frowning-face.png new file mode 100644 index 0000000..3644ff5 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/white-frowning-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/white-smiling-face.png b/uni_modules/cool-cs/static/emoji/white-smiling-face.png new file mode 100644 index 0000000..082b271 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/white-smiling-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/winking-face.png b/uni_modules/cool-cs/static/emoji/winking-face.png new file mode 100644 index 0000000..59c99e0 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/winking-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/worried-face.png b/uni_modules/cool-cs/static/emoji/worried-face.png new file mode 100644 index 0000000..8638920 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/worried-face.png differ diff --git a/uni_modules/cool-cs/static/emoji/zipper-mouth-face.png b/uni_modules/cool-cs/static/emoji/zipper-mouth-face.png new file mode 100644 index 0000000..79e02a3 Binary files /dev/null and b/uni_modules/cool-cs/static/emoji/zipper-mouth-face.png differ diff --git a/uni_modules/cool-cs/static/fn-camera.png b/uni_modules/cool-cs/static/fn-camera.png new file mode 100644 index 0000000..9593ed6 Binary files /dev/null and b/uni_modules/cool-cs/static/fn-camera.png differ diff --git a/uni_modules/cool-cs/static/fn-pic.png b/uni_modules/cool-cs/static/fn-pic.png new file mode 100644 index 0000000..2584560 Binary files /dev/null and b/uni_modules/cool-cs/static/fn-pic.png differ diff --git a/uni_modules/cool-cs/static/minus.png b/uni_modules/cool-cs/static/minus.png new file mode 100644 index 0000000..723dbd8 Binary files /dev/null and b/uni_modules/cool-cs/static/minus.png differ diff --git a/uni_modules/cool-cs/static/plus.png b/uni_modules/cool-cs/static/plus.png new file mode 100644 index 0000000..38acc2c Binary files /dev/null and b/uni_modules/cool-cs/static/plus.png differ diff --git a/uni_modules/cool-cs/types/index.d.ts b/uni_modules/cool-cs/types/index.d.ts new file mode 100644 index 0000000..ec31c09 --- /dev/null +++ b/uni_modules/cool-cs/types/index.d.ts @@ -0,0 +1,16 @@ +export declare namespace Cs { + interface Content { + type: "text" | "image" | "voice" | "video" | "file" | "link" | "location" | "emoji"; + data: string; + } + + interface Msg extends Eps.CsMsgEntity { + content: Content; + sessionId?: number; + } + + interface Session { + id: number; + [key: string]: any; + } +} diff --git a/uni_modules/cool-cs/utils/index.ts b/uni_modules/cool-cs/utils/index.ts new file mode 100644 index 0000000..40f3e27 --- /dev/null +++ b/uni_modules/cool-cs/utils/index.ts @@ -0,0 +1,13 @@ +import dayjs from "dayjs"; + +// 日期格式化 +export function dateFormatter(date?: Date) { + const t = dayjs(date); + + // 在今天之前 + if (t.isBefore(dayjs().hour(0).minute(0).second(0))) { + return t.format("YYYY-MM-DD HH:mm"); + } else { + return t.format("HH:mm"); + } +} diff --git a/uni_modules/cool-ui/changelog.md b/uni_modules/cool-ui/changelog.md new file mode 100644 index 0000000..832eea8 --- /dev/null +++ b/uni_modules/cool-ui/changelog.md @@ -0,0 +1,16 @@ +## 2024-4-27 + +- 优化 cl-switch 组件 + +## 2024-3-13 + +- 添加 cl-select-city 组件 + +## 2024-3-8 + +- 部分组件重构 +- 更新 icon + +## 2024-3-1 + +- [cl-select-date] 解决切换日期时,列数据显示问题 diff --git a/uni_modules/cool-ui/components/cl-action-sheet/cl-action-sheet.vue b/uni_modules/cool-ui/components/cl-action-sheet/cl-action-sheet.vue new file mode 100644 index 0000000..41a9e49 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-action-sheet/cl-action-sheet.vue @@ -0,0 +1,132 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-avatar-group/cl-avatar-group.vue b/uni_modules/cool-ui/components/cl-avatar-group/cl-avatar-group.vue new file mode 100644 index 0000000..c71c87c --- /dev/null +++ b/uni_modules/cool-ui/components/cl-avatar-group/cl-avatar-group.vue @@ -0,0 +1,61 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-avatar/cl-avatar.vue b/uni_modules/cool-ui/components/cl-avatar/cl-avatar.vue new file mode 100644 index 0000000..22a2fc4 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-avatar/cl-avatar.vue @@ -0,0 +1,101 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-badge/cl-badge.vue b/uni_modules/cool-ui/components/cl-badge/cl-badge.vue new file mode 100644 index 0000000..e7fe5d5 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-badge/cl-badge.vue @@ -0,0 +1,77 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-banner/cl-banner.vue b/uni_modules/cool-ui/components/cl-banner/cl-banner.vue new file mode 100644 index 0000000..aa857e8 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-banner/cl-banner.vue @@ -0,0 +1,280 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-button/cl-button.vue b/uni_modules/cool-ui/components/cl-button/cl-button.vue new file mode 100644 index 0000000..2f90066 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-button/cl-button.vue @@ -0,0 +1,179 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-captcha/cl-captcha.vue b/uni_modules/cool-ui/components/cl-captcha/cl-captcha.vue new file mode 100644 index 0000000..50b3612 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-captcha/cl-captcha.vue @@ -0,0 +1,123 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-card/cl-card.vue b/uni_modules/cool-ui/components/cl-card/cl-card.vue new file mode 100644 index 0000000..b184e2c --- /dev/null +++ b/uni_modules/cool-ui/components/cl-card/cl-card.vue @@ -0,0 +1,67 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-checkbox-group/cl-checkbox-group.vue b/uni_modules/cool-ui/components/cl-checkbox-group/cl-checkbox-group.vue new file mode 100644 index 0000000..42a4dbf --- /dev/null +++ b/uni_modules/cool-ui/components/cl-checkbox-group/cl-checkbox-group.vue @@ -0,0 +1,61 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-checkbox/cl-checkbox.vue b/uni_modules/cool-ui/components/cl-checkbox/cl-checkbox.vue new file mode 100644 index 0000000..998f80d --- /dev/null +++ b/uni_modules/cool-ui/components/cl-checkbox/cl-checkbox.vue @@ -0,0 +1,148 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-col/cl-col.vue b/uni_modules/cool-ui/components/cl-col/cl-col.vue new file mode 100644 index 0000000..9e69e8f --- /dev/null +++ b/uni_modules/cool-ui/components/cl-col/cl-col.vue @@ -0,0 +1,65 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-confirm/cl-confirm.vue b/uni_modules/cool-ui/components/cl-confirm/cl-confirm.vue new file mode 100644 index 0000000..715f232 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-confirm/cl-confirm.vue @@ -0,0 +1,173 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-countdown/cl-countdown.vue b/uni_modules/cool-ui/components/cl-countdown/cl-countdown.vue new file mode 100644 index 0000000..9624843 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-countdown/cl-countdown.vue @@ -0,0 +1,273 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-dialog/cl-dialog.vue b/uni_modules/cool-ui/components/cl-dialog/cl-dialog.vue new file mode 100644 index 0000000..7ee6d63 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-dialog/cl-dialog.vue @@ -0,0 +1,110 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-divider/cl-divider.vue b/uni_modules/cool-ui/components/cl-divider/cl-divider.vue new file mode 100644 index 0000000..cf75419 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-divider/cl-divider.vue @@ -0,0 +1,53 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-empty/cl-empty.vue b/uni_modules/cool-ui/components/cl-empty/cl-empty.vue new file mode 100644 index 0000000..1d54518 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-empty/cl-empty.vue @@ -0,0 +1,67 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-filter-bar/cl-filter-bar.vue b/uni_modules/cool-ui/components/cl-filter-bar/cl-filter-bar.vue new file mode 100644 index 0000000..588804a --- /dev/null +++ b/uni_modules/cool-ui/components/cl-filter-bar/cl-filter-bar.vue @@ -0,0 +1,124 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-filter-item/cl-filter-item.vue b/uni_modules/cool-ui/components/cl-filter-item/cl-filter-item.vue new file mode 100644 index 0000000..8e89c61 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-filter-item/cl-filter-item.vue @@ -0,0 +1,343 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-footer/cl-footer.vue b/uni_modules/cool-ui/components/cl-footer/cl-footer.vue new file mode 100644 index 0000000..66d4e94 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-footer/cl-footer.vue @@ -0,0 +1,154 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-form-item/cl-form-item.vue b/uni_modules/cool-ui/components/cl-form-item/cl-form-item.vue new file mode 100644 index 0000000..b78fa5c --- /dev/null +++ b/uni_modules/cool-ui/components/cl-form-item/cl-form-item.vue @@ -0,0 +1,286 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-form/cl-form.vue b/uni_modules/cool-ui/components/cl-form/cl-form.vue new file mode 100644 index 0000000..5d0908b --- /dev/null +++ b/uni_modules/cool-ui/components/cl-form/cl-form.vue @@ -0,0 +1,244 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-grid-item/cl-grid-item.vue b/uni_modules/cool-ui/components/cl-grid-item/cl-grid-item.vue new file mode 100644 index 0000000..66f5dc4 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-grid-item/cl-grid-item.vue @@ -0,0 +1,28 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-grid/cl-grid.vue b/uni_modules/cool-ui/components/cl-grid/cl-grid.vue new file mode 100644 index 0000000..c67d35e --- /dev/null +++ b/uni_modules/cool-ui/components/cl-grid/cl-grid.vue @@ -0,0 +1,31 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-guide/cl-guide.vue b/uni_modules/cool-ui/components/cl-guide/cl-guide.vue new file mode 100644 index 0000000..5d6e21d --- /dev/null +++ b/uni_modules/cool-ui/components/cl-guide/cl-guide.vue @@ -0,0 +1,321 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-icon/cl-icon.vue b/uni_modules/cool-ui/components/cl-icon/cl-icon.vue new file mode 100644 index 0000000..e10305a --- /dev/null +++ b/uni_modules/cool-ui/components/cl-icon/cl-icon.vue @@ -0,0 +1,39 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-image/cl-image.vue b/uni_modules/cool-ui/components/cl-image/cl-image.vue new file mode 100644 index 0000000..82c2304 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-image/cl-image.vue @@ -0,0 +1,178 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-input-number/cl-input-number.vue b/uni_modules/cool-ui/components/cl-input-number/cl-input-number.vue new file mode 100644 index 0000000..65c5a31 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-input-number/cl-input-number.vue @@ -0,0 +1,206 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-input/cl-input.vue b/uni_modules/cool-ui/components/cl-input/cl-input.vue new file mode 100644 index 0000000..444eb0a --- /dev/null +++ b/uni_modules/cool-ui/components/cl-input/cl-input.vue @@ -0,0 +1,238 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-list-index/cl-list-index.vue b/uni_modules/cool-ui/components/cl-list-index/cl-list-index.vue new file mode 100644 index 0000000..bc42c4f --- /dev/null +++ b/uni_modules/cool-ui/components/cl-list-index/cl-list-index.vue @@ -0,0 +1,455 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-list-item/cl-list-item.vue b/uni_modules/cool-ui/components/cl-list-item/cl-list-item.vue new file mode 100644 index 0000000..bd5432f --- /dev/null +++ b/uni_modules/cool-ui/components/cl-list-item/cl-list-item.vue @@ -0,0 +1,258 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-list/cl-list.vue b/uni_modules/cool-ui/components/cl-list/cl-list.vue new file mode 100644 index 0000000..942700b --- /dev/null +++ b/uni_modules/cool-ui/components/cl-list/cl-list.vue @@ -0,0 +1,33 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-loading-mask/cl-loading-mask.vue b/uni_modules/cool-ui/components/cl-loading-mask/cl-loading-mask.vue new file mode 100644 index 0000000..9177e4e --- /dev/null +++ b/uni_modules/cool-ui/components/cl-loading-mask/cl-loading-mask.vue @@ -0,0 +1,64 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-loading/cl-loading.vue b/uni_modules/cool-ui/components/cl-loading/cl-loading.vue new file mode 100644 index 0000000..f18acbb --- /dev/null +++ b/uni_modules/cool-ui/components/cl-loading/cl-loading.vue @@ -0,0 +1,29 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-loadmore/cl-loadmore.vue b/uni_modules/cool-ui/components/cl-loadmore/cl-loadmore.vue new file mode 100644 index 0000000..179ad67 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-loadmore/cl-loadmore.vue @@ -0,0 +1,79 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-noticebar/cl-noticebar.vue b/uni_modules/cool-ui/components/cl-noticebar/cl-noticebar.vue new file mode 100644 index 0000000..5969570 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-noticebar/cl-noticebar.vue @@ -0,0 +1,220 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-page/cl-page.vue b/uni_modules/cool-ui/components/cl-page/cl-page.vue new file mode 100644 index 0000000..32704b2 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-page/cl-page.vue @@ -0,0 +1,231 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-pay/ali.png b/uni_modules/cool-ui/components/cl-pay/ali.png new file mode 100644 index 0000000..94baa08 Binary files /dev/null and b/uni_modules/cool-ui/components/cl-pay/ali.png differ diff --git a/uni_modules/cool-ui/components/cl-pay/cl-pay.vue b/uni_modules/cool-ui/components/cl-pay/cl-pay.vue new file mode 100644 index 0000000..ff472e1 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-pay/cl-pay.vue @@ -0,0 +1,86 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-pay/wx.png b/uni_modules/cool-ui/components/cl-pay/wx.png new file mode 100644 index 0000000..99aab12 Binary files /dev/null and b/uni_modules/cool-ui/components/cl-pay/wx.png differ diff --git a/uni_modules/cool-ui/components/cl-popup/cl-popup.vue b/uni_modules/cool-ui/components/cl-popup/cl-popup.vue new file mode 100644 index 0000000..432a1d2 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-popup/cl-popup.vue @@ -0,0 +1,295 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-progress/cl-progress.vue b/uni_modules/cool-ui/components/cl-progress/cl-progress.vue new file mode 100644 index 0000000..60dfed3 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-progress/cl-progress.vue @@ -0,0 +1,101 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-radio-group/cl-radio-group.vue b/uni_modules/cool-ui/components/cl-radio-group/cl-radio-group.vue new file mode 100644 index 0000000..71d8ee6 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-radio-group/cl-radio-group.vue @@ -0,0 +1,48 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-radio/cl-radio.vue b/uni_modules/cool-ui/components/cl-radio/cl-radio.vue new file mode 100644 index 0000000..626a54b --- /dev/null +++ b/uni_modules/cool-ui/components/cl-radio/cl-radio.vue @@ -0,0 +1,149 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-rate/cl-rate.vue b/uni_modules/cool-ui/components/cl-rate/cl-rate.vue new file mode 100644 index 0000000..07db621 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-rate/cl-rate.vue @@ -0,0 +1,138 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-row/cl-row.vue b/uni_modules/cool-ui/components/cl-row/cl-row.vue new file mode 100644 index 0000000..2cfe563 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-row/cl-row.vue @@ -0,0 +1,79 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-scroller/cl-scroller.vue b/uni_modules/cool-ui/components/cl-scroller/cl-scroller.vue new file mode 100644 index 0000000..a320b2c --- /dev/null +++ b/uni_modules/cool-ui/components/cl-scroller/cl-scroller.vue @@ -0,0 +1,261 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-search/cl-search.vue b/uni_modules/cool-ui/components/cl-search/cl-search.vue new file mode 100644 index 0000000..c58f040 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-search/cl-search.vue @@ -0,0 +1,207 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-select-city/cl-select-city.vue b/uni_modules/cool-ui/components/cl-select-city/cl-select-city.vue new file mode 100644 index 0000000..77a191f --- /dev/null +++ b/uni_modules/cool-ui/components/cl-select-city/cl-select-city.vue @@ -0,0 +1,305 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-select-date/cl-select-date.vue b/uni_modules/cool-ui/components/cl-select-date/cl-select-date.vue new file mode 100644 index 0000000..5603176 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-select-date/cl-select-date.vue @@ -0,0 +1,280 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-select-inner/cl-select-inner.vue b/uni_modules/cool-ui/components/cl-select-inner/cl-select-inner.vue new file mode 100644 index 0000000..672f72c --- /dev/null +++ b/uni_modules/cool-ui/components/cl-select-inner/cl-select-inner.vue @@ -0,0 +1,53 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-select-inner/config.ts b/uni_modules/cool-ui/components/cl-select-inner/config.ts new file mode 100644 index 0000000..f14f2f5 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-select-inner/config.ts @@ -0,0 +1,35 @@ +export const Props = { + // 组件高 + height: [String, Number], + // 占位文本 + placeholder: { + type: String, + default: "请选择", + }, + // 是否禁用 + disabled: { + type: Boolean, + default: null, + }, + // 是否带有边框 + border: { + type: Boolean, + default: true, + }, + // 是否圆角 + round: { + type: Boolean, + default: null, + }, + // 图标 + arrowIcon: { + type: String, + default: "cl-icon-arrow-bottom", + }, + // 背景色 + backgroundColor: String, + // 圆角边框 + borderRadius: [String, Number, Array], + // 内间距 + padding: [String, Number, Array], +}; diff --git a/uni_modules/cool-ui/components/cl-select-popup/cl-select-popup.vue b/uni_modules/cool-ui/components/cl-select-popup/cl-select-popup.vue new file mode 100644 index 0000000..e9e305e --- /dev/null +++ b/uni_modules/cool-ui/components/cl-select-popup/cl-select-popup.vue @@ -0,0 +1,298 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-select-region/cl-select-region.vue b/uni_modules/cool-ui/components/cl-select-region/cl-select-region.vue new file mode 100644 index 0000000..1a6704c --- /dev/null +++ b/uni_modules/cool-ui/components/cl-select-region/cl-select-region.vue @@ -0,0 +1,145 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-select/cl-select.vue b/uni_modules/cool-ui/components/cl-select/cl-select.vue new file mode 100644 index 0000000..fb7b6f1 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-select/cl-select.vue @@ -0,0 +1,236 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-service/cl-service.vue b/uni_modules/cool-ui/components/cl-service/cl-service.vue new file mode 100644 index 0000000..8ff5bb2 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-service/cl-service.vue @@ -0,0 +1,77 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-share-popup/cl-share-popup.vue b/uni_modules/cool-ui/components/cl-share-popup/cl-share-popup.vue new file mode 100644 index 0000000..ddfbf61 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-share-popup/cl-share-popup.vue @@ -0,0 +1,72 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-share/alipay.png b/uni_modules/cool-ui/components/cl-share/alipay.png new file mode 100644 index 0000000..94baa08 Binary files /dev/null and b/uni_modules/cool-ui/components/cl-share/alipay.png differ diff --git a/uni_modules/cool-ui/components/cl-share/cl-share.vue b/uni_modules/cool-ui/components/cl-share/cl-share.vue new file mode 100644 index 0000000..3d991ed --- /dev/null +++ b/uni_modules/cool-ui/components/cl-share/cl-share.vue @@ -0,0 +1,130 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-share/qq.png b/uni_modules/cool-ui/components/cl-share/qq.png new file mode 100644 index 0000000..f115924 Binary files /dev/null and b/uni_modules/cool-ui/components/cl-share/qq.png differ diff --git a/uni_modules/cool-ui/components/cl-share/wx.png b/uni_modules/cool-ui/components/cl-share/wx.png new file mode 100644 index 0000000..99aab12 Binary files /dev/null and b/uni_modules/cool-ui/components/cl-share/wx.png differ diff --git a/uni_modules/cool-ui/components/cl-share/wx2.png b/uni_modules/cool-ui/components/cl-share/wx2.png new file mode 100644 index 0000000..61072c7 Binary files /dev/null and b/uni_modules/cool-ui/components/cl-share/wx2.png differ diff --git a/uni_modules/cool-ui/components/cl-skeleton/cl-skeleton.vue b/uni_modules/cool-ui/components/cl-skeleton/cl-skeleton.vue new file mode 100644 index 0000000..2b0030a --- /dev/null +++ b/uni_modules/cool-ui/components/cl-skeleton/cl-skeleton.vue @@ -0,0 +1,39 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-slider/cl-slider.vue b/uni_modules/cool-ui/components/cl-slider/cl-slider.vue new file mode 100644 index 0000000..f50fec0 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-slider/cl-slider.vue @@ -0,0 +1,110 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-status-bar/cl-status-bar.vue b/uni_modules/cool-ui/components/cl-status-bar/cl-status-bar.vue new file mode 100644 index 0000000..5865297 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-status-bar/cl-status-bar.vue @@ -0,0 +1,64 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-sticky/cl-sticky.vue b/uni_modules/cool-ui/components/cl-sticky/cl-sticky.vue new file mode 100644 index 0000000..081f04f --- /dev/null +++ b/uni_modules/cool-ui/components/cl-sticky/cl-sticky.vue @@ -0,0 +1,69 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-switch/cl-switch.vue b/uni_modules/cool-ui/components/cl-switch/cl-switch.vue new file mode 100644 index 0000000..521e05b --- /dev/null +++ b/uni_modules/cool-ui/components/cl-switch/cl-switch.vue @@ -0,0 +1,64 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-tabs/cl-tabs.vue b/uni_modules/cool-ui/components/cl-tabs/cl-tabs.vue new file mode 100644 index 0000000..ffb692f --- /dev/null +++ b/uni_modules/cool-ui/components/cl-tabs/cl-tabs.vue @@ -0,0 +1,367 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-tag/cl-tag.vue b/uni_modules/cool-ui/components/cl-tag/cl-tag.vue new file mode 100644 index 0000000..759c05e --- /dev/null +++ b/uni_modules/cool-ui/components/cl-tag/cl-tag.vue @@ -0,0 +1,80 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-text/cl-text.vue b/uni_modules/cool-ui/components/cl-text/cl-text.vue new file mode 100644 index 0000000..42dbb98 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-text/cl-text.vue @@ -0,0 +1,167 @@ + + + diff --git a/uni_modules/cool-ui/components/cl-textarea/cl-textarea.vue b/uni_modules/cool-ui/components/cl-textarea/cl-textarea.vue new file mode 100644 index 0000000..277d5a7 --- /dev/null +++ b/uni_modules/cool-ui/components/cl-textarea/cl-textarea.vue @@ -0,0 +1,201 @@ +