wangrong
5 小时以前 a611c225b17219e873b60888e03c330fbe0c57a4
修改了首页手机号授权
2个文件已添加
15个文件已修改
714 ■■■■■ 已修改文件
README.md 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/phone-auth.vue 193 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manifest.json 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages.json 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/index/components/tabbar.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/recycle/appointment.vue 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/recycle/banner.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/recycle/home.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/recycle/record.vue 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pnpm-lock.yaml 179 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pnpm-workspace.yaml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
static/css/iconfont/index.scss 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/cool-ui/static/css/col.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/cool-ui/static/css/form.scss 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
uni_modules/cool-ui/static/iconfont/index.scss 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite.config.ts 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
README.md
@@ -9,6 +9,10 @@
#### 启动快
基于 `vite`,快速的冷启动,不需要等待打包,即时的热模块更新,真正的按需编译。
pnpm install
pnpm approve-builds
空格选中 esbuild 和 vue-demi,回车确认。
pnpm add dijkstrajs
#### 开发快
components/phone-auth.vue
New file
@@ -0,0 +1,193 @@
<template>
    <!-- #ifdef MP-WEIXIN -->
    <view class="phone-auth" v-if="visible">
        <view class="phone-auth__mask" @tap="later"></view>
        <view class="phone-auth__panel">
            <text class="phone-auth__title">授权手机号</text>
            <text class="phone-auth__desc">
                回收、预约等功能需要使用您的手机号。请授权后再继续使用。
            </text>
            <button
                class="phone-auth__btn"
                open-type="getPhoneNumber"
                @getphonenumber="onGetPhone"
            >
                登录并授权手机号
            </button>
            <view class="phone-auth__later" @tap="later">暂不授权</view>
        </view>
    </view>
    <!-- #endif -->
</template>
<script lang="ts" setup>
import { computed, ref } from "vue";
import { onShow } from "@dcloudio/uni-app";
import { useCool, useStore, useWx } from "/@/cool";
import { useUi } from "/$/cool-ui";
const authState = ((globalThis as any).__phoneAuthState ||= { dismissed: false });
const { service, router } = useCool();
const { user } = useStore();
const wx = useWx();
const ui = useUi();
const tick = ref(0);
const submitting = ref(false);
const visible = computed(() => {
    tick.value;
    return !authState.dismissed && !user.info?.phone;
});
function later() {
    authState.dismissed = true;
    tick.value++;
}
function phonePayload(detail: { code?: string; encryptedData?: string; iv?: string }) {
    // 新版手机号按钮只返回动态令牌,必须原样提交,不能换成 wx.login 的 code
    if (detail.code && !detail.encryptedData) {
        return { code: detail.code };
    }
    return {
        encryptedData: detail.encryptedData,
        iv: detail.iv,
        code: wx.code.value,
    };
}
function enterHome(phone: string) {
    user.set({
        ...(user.info || {}),
        phone,
    });
    authState.dismissed = true;
    tick.value++;
    router.home();
}
function onGetPhone(e: {
    detail: { errMsg?: string; code?: string; encryptedData?: string; iv?: string };
}) {
    const detail = e.detail || {};
    const errMsg = detail.errMsg || "";
    if (errMsg.indexOf("ok") < 0) {
        ui.showToast("未授权手机号");
        return;
    }
    if (!detail.code && !detail.encryptedData) {
        ui.showToast("未获取到手机号");
        return;
    }
    if (submitting.value) {
        return;
    }
    submitting.value = true;
    ui.showLoading();
    const payload = phonePayload(detail);
    const task = user.token
        ? service.user.info.miniPhone(payload).then(async (phone: string) => {
                const info = user.info || (await service.user.info.person());
                if (info) {
                    user.set({ ...info, phone });
                }
                return phone;
            })
        : service.user.login.miniPhone(payload).then(async (res) => {
                user.setToken(res);
                const info = await service.user.info.person();
                if (info) {
                    user.set(info);
                }
                return info?.phone as string | undefined;
            });
    task
        .then((phone) => {
            ui.hideLoading();
            submitting.value = false;
            if (!phone) {
                ui.showToast("未获取到手机号");
                return;
            }
            enterHome(phone);
        })
        .catch((err) => {
            ui.hideLoading();
            submitting.value = false;
            ui.showToast(err?.message || "手机号授权失败");
        });
}
onShow(() => {
    tick.value++;
});
</script>
<style lang="scss" scoped>
.phone-auth {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 10000;
    &__mask {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        background: rgba(0, 0, 0, 0.45);
    }
    &__panel {
        position: absolute;
        left: 48rpx;
        right: 48rpx;
        top: 30%;
        background: #fff;
        border-radius: 24rpx;
        padding: 48rpx 40rpx 36rpx;
        display: flex;
        flex-direction: column;
        align-items: center;
    }
    &__title {
        font-size: 34rpx;
        font-weight: 600;
        color: #222;
    }
    &__desc {
        margin-top: 20rpx;
        font-size: 26rpx;
        line-height: 1.6;
        color: #666;
        text-align: center;
    }
    &__btn {
        margin-top: 36rpx;
        width: 100%;
        height: 84rpx;
        line-height: 84rpx;
        border-radius: 42rpx;
        background: #2ecc71;
        color: #fff;
        font-size: 30rpx;
        border: 0;
    }
    &__later {
        margin-top: 24rpx;
        font-size: 26rpx;
        color: #999;
    }
}
</style>
manifest.json
@@ -47,11 +47,7 @@
                    "<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
                ],
                "abiFilters": [
                    "armeabi-v7a",
                    "arm64-v8a",
                    "x86"
                ]
                "abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ]
            },
            "ios": {
                "capabilities": {
@@ -68,16 +64,10 @@
            "sdkConfigs": {
                "payment": {
                    "alipay": {
                        "__platform__": [
                            "ios",
                            "android"
                        ]
                        "__platform__" : [ "ios", "android" ]
                    },
                    "weixin": {
                        "__platform__": [
                            "ios",
                            "android"
                        ],
                        "__platform__" : [ "ios", "android" ],
                        "appid": "wx348f72db1512fa2e",
                        "UniversalLinks": ""
                    }
@@ -99,10 +89,7 @@
                },
                "geolocation": {
                    "system": {
                        "__platform__": [
                            "ios",
                            "android"
                        ]
                        "__platform__" : [ "ios", "android" ]
                    }
                },
                "push": {
@@ -164,7 +151,7 @@
    },
    "quickapp": {},
    "mp-weixin": {
        "appid": "wxdebc4de0b5584ca4",
        "appid" : "wx88c344d1b0db243a",
        "setting": {
            "urlCheck": true,
            "es6": false
package.json
@@ -6,6 +6,7 @@
        "@dcloudio/uni-app": "3.0.0-3081220230817001",
        "@hyoga/uni-socket.io": "^3.0.4",
        "dayjs": "^1.11.13",
        "dijkstrajs": "^1.0.3",
        "js-pinyin": "^0.2.5",
        "lodash-es": "^4.17.21",
        "md5": "^2.3.0",
pages.json
@@ -34,6 +34,27 @@
                "navigationBarTitleText": "我的",
                "navigationBarTextStyle": "white"
            }
        },
        {
            "path": "pages/recycle/record",
            "style": {
                "navigationBarTitleText": "回收记录",
                "enablePullDownRefresh": true
            }
        },
        {
            "path": "pages/recycle/appointment",
            "style": {
                "navigationBarTitleText": "预约回收",
                "enablePullDownRefresh": true
            }
        },
        {
            "path": "pages/recycle/transfer",
            "style": {
                "navigationBarTitleText": "转赠记录",
                "enablePullDownRefresh": true
            }
        }
    ],
    "subPackages": [
@@ -104,32 +125,6 @@
                    "path": "coupon",
                    "style": {
                        "navigationBarTitleText": "我的优惠券",
                        "enablePullDownRefresh": true
                    }
                }
            ]
        },
        {
            "root": "pages/recycle",
            "pages": [
                {
                    "path": "record",
                    "style": {
                        "navigationBarTitleText": "回收记录",
                        "enablePullDownRefresh": true
                    }
                },
                {
                    "path": "appointment",
                    "style": {
                        "navigationBarTitleText": "预约回收",
                        "enablePullDownRefresh": true
                    }
                },
                {
                    "path": "transfer",
                    "style": {
                        "navigationBarTitleText": "转赠记录",
                        "enablePullDownRefresh": true
                    }
                }
@@ -278,26 +273,31 @@
        "list": [
            {
                "pagePath": "pages/index/home",
                "text": "首页",
                "iconPath": "static/icon/tabbar/home.png",
                "selectedIconPath": "static/icon/tabbar/home2.png"
            },
            {
                "pagePath": "pages/recycle/home",
                "text": "回收",
                "iconPath": "static/icon/tabbar/recycle.png",
                "selectedIconPath": "static/icon/tabbar/recycle2.png"
            },
            {
                "pagePath": "pages/index/category",
                "text": "分类",
                "iconPath": "static/icon/tabbar/category.png",
                "selectedIconPath": "static/icon/tabbar/category2.png"
            },
            {
                "pagePath": "pages/index/shopping-cart",
                "text": "购物车",
                "iconPath": "static/icon/tabbar/shopping-cart.png",
                "selectedIconPath": "static/icon/tabbar/shopping-cart2.png"
            },
            {
                "pagePath": "pages/index/my",
                "text": "我的",
                "iconPath": "static/icon/tabbar/my.png",
                "selectedIconPath": "static/icon/tabbar/my2.png"
            }
pages/index/components/tabbar.vue
@@ -26,12 +26,14 @@
            </view>
        </view>
    </cl-footer>
    <phone-auth />
</template>
<script lang="ts" setup>
import { computed, onMounted, ref } from "vue";
import { useCool } from "/@/cool";
import { useShoppingCart } from "/@/hooks";
import PhoneAuth from "/@/components/phone-auth.vue";
const { router } = useCool();
const spCart = useShoppingCart();
pages/recycle/appointment.vue
@@ -38,7 +38,7 @@
                    >
                        <view class="card-header">
                            <text class="order-no">单号:{{ item.appointmentNo }}</text>
                            <text class="status" :class="`status-${item.status}`">
                            <text class="status" :class="statusClass(item.status)">
                                {{ item.status }}
                            </text>
                        </view>
@@ -278,6 +278,20 @@
] as const;
type TabValue = (typeof tabs)[number]["value"];
const statusClassMap: Record<string, string> = {
    待审核: "is-review",
    待接单: "is-wait",
    已接单: "is-accepted",
    上门中: "is-visiting",
    已完成: "is-done",
    已取消: "is-cancel",
    已预约: "is-booked",
};
function statusClass(status?: string) {
    return statusClassMap[status || ""] || "";
}
const activeTab = ref<TabValue>("booked");
const list = ref<Eps.RecycleAppointmentEntity[]>([]);
@@ -675,21 +689,21 @@
        background: #f5f5f5;
        color: #999;
        &.status-待审核,
        &.status-待接单 {
        &.is-review,
        &.is-wait {
            background: #fef5e7;
            color: #e67e22;
        }
        &.status-已接单,
        &.status-上门中 {
        &.is-accepted,
        &.is-visiting {
            background: #eaf4fc;
            color: #2980b9;
        }
        &.status-已完成 {
        &.is-done {
            background: #e8f8f0;
            color: #27ae60;
        }
        &.status-已取消 {
        &.is-cancel {
            background: #fef0f0;
            color: #e74c3c;
        }
pages/recycle/banner.vue
@@ -191,7 +191,10 @@
            .dashboard-bg {
                position: absolute;
                inset: 0;
                top: 0;
                right: 0;
                bottom: 0;
                left: 0;
                background: linear-gradient(135deg, #2ecc71 0%, #27ae60 100%);
                z-index: 0;
            }
pages/recycle/home.vue
@@ -87,6 +87,7 @@
            </view>
        </cl-popup>
    </view>
    <phone-auth />
</template>
<script lang="ts" setup>
@@ -95,6 +96,7 @@
    import { onReady, onShareAppMessage } from "@dcloudio/uni-app";
    import { generateRecycleQrcode } from "/@/cool/utils/qrcode";
    import PhoneAuth from "/@/components/phone-auth.vue";
    const { user } = useStore();
@@ -196,7 +198,10 @@
            .dashboard-bg {
                position: absolute;
                inset: 0;
                top: 0;
                right: 0;
                bottom: 0;
                left: 0;
                background: linear-gradient(135deg, #2ecc71 0%, #27ae60 100%);
                z-index: 0;
            }
pages/recycle/record.vue
@@ -36,7 +36,7 @@
                    >
                        <view class="card-header">
                            <text class="order-no">单号:{{ item.orderNo }}</text>
                            <text class="status" :class="`status-${item.status}`">
                            <text class="status" :class="statusClass(item.status)">
                                {{ item.status }}
                            </text>
                        </view>
@@ -204,6 +204,17 @@
    }
}
const statusClassMap: Record<string, string> = {
    待处理: "is-pending",
    进行中: "is-doing",
    已完成: "is-done",
    已取消: "is-cancel",
};
function statusClass(status?: string) {
    return statusClassMap[status || ""] || "";
}
function isExpanded(item: Eps.RecycleOrderEntity) {
    return !!item.orderNo && expandedOrderNo.value === item.orderNo;
}
@@ -349,19 +360,19 @@
            background: #f5f5f5;
            color: #999;
            &.status-待处理 {
            &.is-pending {
                background: #fef5e7;
                color: #e67e22;
            }
            &.status-进行中 {
            &.is-doing {
                background: #eaf4fc;
                color: #2980b9;
            }
            &.status-已完成 {
            &.is-done {
                background: #e8f8f0;
                color: #27ae60;
            }
            &.status-已取消 {
            &.is-cancel {
                background: #fef0f0;
                color: #e74c3c;
            }
pnpm-lock.yaml
@@ -17,6 +17,9 @@
      dayjs:
        specifier: ^1.11.13
        version: 1.11.13
      dijkstrajs:
        specifier: ^1.0.3
        version: 1.0.3
      js-pinyin:
        specifier: ^0.2.5
        version: 0.2.7
@@ -29,6 +32,9 @@
      pinia:
        specifier: ^2.1.7
        version: 2.3.1(typescript@5.5.4)(vue@3.5.13(typescript@5.5.4))
      qrcode:
        specifier: ^1.5.4
        version: 1.5.4
      vue:
        specifier: ^3.5.13
        version: 3.5.13(typescript@5.5.4)
@@ -41,7 +47,7 @@
    devDependencies:
      '@cool-vue/vite-plugin':
        specifier: ^8.0.3
        version: 8.0.3
        version: 8.0.3(debug@4.4.0)
      '@dcloudio/types':
        specifier: ^3.4.14
        version: 3.4.14
@@ -762,6 +768,10 @@
    engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
    hasBin: true
  camelcase@5.3.1:
    resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
    engines: {node: '>=6'}
  caniuse-lite@1.0.30001698:
    resolution: {integrity: sha512-xJ3km2oiG/MbNU8G6zIq6XRZ6HtAOVXsbOrP/blGazi52kc5Yy7b6sDA5O+FbROzRrV7BSTllLHuNvmawYUJjw==}
@@ -771,6 +781,9 @@
  chokidar@3.6.0:
    resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
    engines: {node: '>= 8.10.0'}
  cliui@6.0.0:
    resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
  color-convert@2.0.1:
    resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
@@ -839,9 +852,16 @@
      supports-color:
        optional: true
  decamelize@1.2.0:
    resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
    engines: {node: '>=0.10.0'}
  delayed-stream@1.0.0:
    resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
    engines: {node: '>=0.4.0'}
  dijkstrajs@1.0.3:
    resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
  dom-serializer@2.0.0:
    resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
@@ -903,6 +923,10 @@
    resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
    engines: {node: '>=8'}
  find-up@4.1.0:
    resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
    engines: {node: '>=8'}
  follow-redirects@1.15.9:
    resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
    engines: {node: '>=4.0'}
@@ -942,12 +966,17 @@
    resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
    engines: {node: '>=6.9.0'}
  get-caller-file@2.0.5:
    resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
    engines: {node: 6.* || 8.* || >= 10.*}
  glob-parent@5.1.2:
    resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
    engines: {node: '>= 6'}
  glob@10.4.5:
    resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
    deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
    hasBin: true
  globals@11.12.0:
@@ -1048,6 +1077,10 @@
    resolution: {integrity: sha512-m4iHVZxFH5734oQcPKU08025gIz2+4bjWR9lulP8ZYxEJR0BpA0w32oJmkzh8y3UI9ci7xCBehQDc3oA1X+VHw==}
    engines: {node: '>=6'}
  locate-path@5.0.0:
    resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
    engines: {node: '>=8'}
  lodash-es@4.17.21:
    resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
@@ -1139,8 +1172,24 @@
    resolution: {integrity: sha512-Sv0OvhPiMutICiwORAUefv02DCPb62IelBmo8ZsSrRHyI3FStqIWZvjqDkvtjU+lcujo7UNir+dCwKSqlEQ/5w==}
    engines: {node: '>=10', yarn: ^1.22.4}
  p-limit@2.3.0:
    resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
    engines: {node: '>=6'}
  p-locate@4.1.0:
    resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
    engines: {node: '>=8'}
  p-try@2.2.0:
    resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
    engines: {node: '>=6'}
  package-json-from-dist@1.0.1:
    resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==}
  path-exists@4.0.0:
    resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
    engines: {node: '>=8'}
  path-key@3.1.1:
    resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
@@ -1172,6 +1221,10 @@
    peerDependenciesMeta:
      typescript:
        optional: true
  pngjs@5.0.0:
    resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
    engines: {node: '>=10.13.0'}
  postcss-import@14.1.0:
    resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==}
@@ -1243,6 +1296,11 @@
  proxy-from-env@1.1.0:
    resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
  qrcode@1.5.4:
    resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==}
    engines: {node: '>=10.13.0'}
    hasBin: true
  queue-microtask@1.2.3:
    resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@@ -1252,6 +1310,13 @@
  readdirp@3.6.0:
    resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
    engines: {node: '>=8.10.0'}
  require-directory@2.1.1:
    resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
    engines: {node: '>=0.10.0'}
  require-main-filename@2.0.0:
    resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
  resolve@1.22.10:
    resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
@@ -1276,6 +1341,9 @@
  semver@6.3.1:
    resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
    hasBin: true
  set-blocking@2.0.0:
    resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
  shebang-command@2.0.0:
    resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
@@ -1403,6 +1471,7 @@
  vue-i18n@9.1.9:
    resolution: {integrity: sha512-JeRdNVxS2OGp1E+pye5XB6+M6BBkHwAv9C80Q7+kzoMdUDGRna06tjC0vCB/jDX9aWrl5swxOMFcyAr7or8XTA==}
    engines: {node: '>= 10'}
    deprecated: v9 and v10 no longer supported. please migrate to v11. about maintenance status, see https://vue-i18n.intlify.dev/guide/maintenance.html
    peerDependencies:
      vue: ^3.0.0
@@ -1422,10 +1491,17 @@
  weixin-js-sdk@1.6.5:
    resolution: {integrity: sha512-Gph1WAWB2YN/lMOFB/ymb+hbU/wYazzJgu6PMMktCy9cSCeW5wA6Zwt0dpahJbJ+RJEwtTv2x9iIu0U4enuVSQ==}
  which-module@2.0.1:
    resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
  which@2.0.2:
    resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
    engines: {node: '>= 8'}
    hasBin: true
  wrap-ansi@6.2.0:
    resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
    engines: {node: '>=8'}
  wrap-ansi@7.0.0:
    resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
@@ -1442,12 +1518,23 @@
  xregexp@3.1.0:
    resolution: {integrity: sha512-4Y1x6DyB8xRoxosooa6PlGWqmmSKatbzhrftZ7Purmm4B8R4qIEJG1A2hZsdz5DhmIqS0msC0I7KEq93GphEVg==}
  y18n@4.0.3:
    resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
  yallist@3.1.1:
    resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
  yaml@1.10.2:
    resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
    engines: {node: '>= 6'}
  yargs-parser@18.1.3:
    resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
    engines: {node: '>=6'}
  yargs@15.4.1:
    resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
    engines: {node: '>=8'}
snapshots:
@@ -1555,10 +1642,10 @@
      '@babel/helper-string-parser': 7.25.9
      '@babel/helper-validator-identifier': 7.25.9
  '@cool-vue/vite-plugin@8.0.3':
  '@cool-vue/vite-plugin@8.0.3(debug@4.4.0)':
    dependencies:
      '@vue/compiler-sfc': 3.5.13
      axios: 1.7.9
      axios: 1.7.9(debug@4.4.0)
      glob: 10.4.5
      lodash: 4.17.21
      magic-string: 0.30.17
@@ -2153,9 +2240,9 @@
      postcss: 8.5.1
      postcss-value-parser: 4.2.0
  axios@1.7.9:
  axios@1.7.9(debug@4.4.0):
    dependencies:
      follow-redirects: 1.15.9
      follow-redirects: 1.15.9(debug@4.4.0)
      form-data: 4.0.1
      proxy-from-env: 1.1.0
    transitivePeerDependencies:
@@ -2184,6 +2271,8 @@
      node-releases: 2.0.19
      update-browserslist-db: 1.1.2(browserslist@4.24.4)
  camelcase@5.3.1: {}
  caniuse-lite@1.0.30001698: {}
  charenc@0.0.2: {}
@@ -2199,6 +2288,12 @@
      readdirp: 3.6.0
    optionalDependencies:
      fsevents: 2.3.3
  cliui@6.0.0:
    dependencies:
      string-width: 4.2.3
      strip-ansi: 6.0.1
      wrap-ansi: 6.2.0
  color-convert@2.0.1:
    dependencies:
@@ -2258,7 +2353,11 @@
    dependencies:
      ms: 2.1.3
  decamelize@1.2.0: {}
  delayed-stream@1.0.0: {}
  dijkstrajs@1.0.3: {}
  dom-serializer@2.0.0:
    dependencies:
@@ -2361,7 +2460,14 @@
    dependencies:
      to-regex-range: 5.0.1
  follow-redirects@1.15.9: {}
  find-up@4.1.0:
    dependencies:
      locate-path: 5.0.0
      path-exists: 4.0.0
  follow-redirects@1.15.9(debug@4.4.0):
    optionalDependencies:
      debug: 4.4.0
  foreground-child@3.3.0:
    dependencies:
@@ -2392,6 +2498,8 @@
      loader-utils: 3.3.1
  gensync@1.0.0-beta.2: {}
  get-caller-file@2.0.5: {}
  glob-parent@5.1.2:
    dependencies:
@@ -2478,6 +2586,10 @@
  localstorage-polyfill@1.0.1: {}
  locate-path@5.0.0:
    dependencies:
      p-locate: 4.1.0
  lodash-es@4.17.21: {}
  lodash.camelcase@4.3.0: {}
@@ -2551,7 +2663,19 @@
    dependencies:
      lcid: 3.1.1
  p-limit@2.3.0:
    dependencies:
      p-try: 2.2.0
  p-locate@4.1.0:
    dependencies:
      p-limit: 2.3.0
  p-try@2.2.0: {}
  package-json-from-dist@1.0.1: {}
  path-exists@4.0.0: {}
  path-key@3.1.1: {}
@@ -2577,6 +2701,8 @@
      typescript: 5.5.4
    transitivePeerDependencies:
      - '@vue/composition-api'
  pngjs@5.0.0: {}
  postcss-import@14.1.0(postcss@8.5.1):
    dependencies:
@@ -2647,6 +2773,12 @@
  proxy-from-env@1.1.0: {}
  qrcode@1.5.4:
    dependencies:
      dijkstrajs: 1.0.3
      pngjs: 5.0.0
      yargs: 15.4.1
  queue-microtask@1.2.3: {}
  read-cache@1.0.0:
@@ -2656,6 +2788,10 @@
  readdirp@3.6.0:
    dependencies:
      picomatch: 2.3.1
  require-directory@2.1.1: {}
  require-main-filename@2.0.0: {}
  resolve@1.22.10:
    dependencies:
@@ -2697,6 +2833,8 @@
  safe-area-insets@1.4.1: {}
  semver@6.3.1: {}
  set-blocking@2.0.0: {}
  shebang-command@2.0.0:
    dependencies:
@@ -2804,9 +2942,17 @@
  weixin-js-sdk@1.6.5: {}
  which-module@2.0.1: {}
  which@2.0.2:
    dependencies:
      isexe: 2.0.0
  wrap-ansi@6.2.0:
    dependencies:
      ansi-styles: 4.3.0
      string-width: 4.2.3
      strip-ansi: 6.0.1
  wrap-ansi@7.0.0:
    dependencies:
@@ -2824,6 +2970,27 @@
  xregexp@3.1.0: {}
  y18n@4.0.3: {}
  yallist@3.1.1: {}
  yaml@1.10.2: {}
  yargs-parser@18.1.3:
    dependencies:
      camelcase: 5.3.1
      decamelize: 1.2.0
  yargs@15.4.1:
    dependencies:
      cliui: 6.0.0
      decamelize: 1.2.0
      find-up: 4.1.0
      get-caller-file: 2.0.5
      require-directory: 2.1.1
      require-main-filename: 2.0.0
      set-blocking: 2.0.0
      string-width: 4.2.3
      which-module: 2.0.1
      y18n: 4.0.3
      yargs-parser: 18.1.3
pnpm-workspace.yaml
New file
@@ -0,0 +1,3 @@
allowBuilds:
  esbuild: true
  vue-demi: true
static/css/iconfont/index.scss
@@ -1,12 +1,38 @@
@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");
    src: url("font.woff2") format("woff2");
}
[class*="shop-icon-"] {
.shop-icon-list:before,
.shop-icon-list2:before,
.shop-icon-order-close:before,
.shop-icon-order-success:before,
.shop-icon-order-comment:before,
.shop-icon-order-received:before,
.shop-icon-order-paid:before,
.shop-icon-order-not-shipped:before,
.shop-icon-order-refund:before,
.shop-icon-order-received2:before,
.shop-icon-zoom:before,
.shop-icon-sku:before,
.shop-icon-set:before,
.shop-icon-home:before,
.shop-icon-shopping-cart:before,
.shop-icon-more:before,
.shop-icon-q-order:before,
.shop-icon-q-pay:before,
.shop-icon-q-refund:before,
.shop-icon-q-logistics:before,
.shop-icon-setting:before,
.shop-icon-coupon:before,
.shop-icon-order:before,
.shop-icon-location:before,
.shop-icon-filter:before,
.shop-icon-message:before,
.shop-icon-delete:before,
.shop-icon-sort:before,
.shop-icon-search:before,
.shop-icon-custom:before {
    font-family: "shop-iconfont";
    font-size: inherit;
    font-style: normal;
uni_modules/cool-ui/static/css/col.scss
@@ -2,17 +2,13 @@
.cl-col {
    width: 100%;
    float: left;
    box-sizing: border-box;
    &::before {
        content: "";
        display: block;
    }
}
[class*="cl-col-"] {
    float: left;
    box-sizing: border-box;
}
.cl-col-0 {
uni_modules/cool-ui/static/css/form.scss
@@ -7,7 +7,7 @@
        &.is-required {
            .cl-form-item__label::after {
                content: "*";
                content: "\\002a";
                color: $cl-color-error;
                margin-left: 6rpx;
            }
uni_modules/cool-ui/static/iconfont/index.scss
@@ -1,17 +1,129 @@
@import "./iconfont.scss";
@font-face {
.cl-icon-tab-home:before,
.cl-icon-tab-my:before,
.cl-icon-image:before,
.cl-icon-map:before,
.cl-icon-sound:before,
.cl-icon-mute:before,
.cl-icon-set:before,
.cl-icon-calendar:before,
.cl-icon-delete:before,
.cl-icon-order-refund:before,
.cl-icon-order-paid:before,
.cl-icon-exit:before,
.cl-icon-folder:before,
.cl-icon-qrcode:before,
.cl-icon-msg:before,
.cl-icon-order-received:before,
.cl-icon-order-not-shipped:before,
.cl-icon-app:before,
.cl-icon-payment:before,
.cl-icon-face-auth:before,
.cl-icon-bill:before,
.cl-icon-phone:before,
.cl-icon-loading:before,
.cl-icon-home:before,
.cl-icon-pause:before,
.cl-icon-amount-fill:before,
.cl-icon-wallet-fill:before,
.cl-icon-doc-fill:before,
.cl-icon-good-fill:before,
.cl-icon-camera-fill:before,
.cl-icon-mail-fill:before,
.cl-icon-bank-card-fill:before,
.cl-icon-relay-fill:before,
.cl-icon-comment-fill:before,
.cl-icon-share:before,
.cl-icon-link:before,
.cl-icon-back:before,
.cl-icon-enter:before,
.cl-icon-top:before,
.cl-icon-upgrade:before,
.cl-icon-rise:before,
.cl-icon-decline:before,
.cl-icon-active:before,
.cl-icon-shrink:before,
.cl-icon-cropper:before,
.cl-icon-fullscreen:before,
.cl-icon-enlarge:before,
.cl-icon-chart-pie:before,
.cl-icon-warning:before,
.cl-icon-arrow-double-left:before,
.cl-icon-arrow-double-right:before,
.cl-icon-like-fill:before,
.cl-icon-like:before,
.cl-icon-my:before,
.cl-icon-eye-open:before,
.cl-icon-friend:before,
.cl-icon-eye-close:before,
.cl-icon-cloud-download:before,
.cl-icon-cloud-upload:before,
.cl-icon-chart-bar:before,
.cl-icon-clock-fill:before,
.cl-icon-favor-fill:before,
.cl-icon-help-fill:before,
.cl-icon-history-fill:before,
.cl-icon-smile-fill:before,
.cl-icon-success-fill:before,
.cl-icon-location-fill:before,
.cl-icon-prompt-fill:before,
.cl-icon-meh-fill:before,
.cl-icon-cry-fill:before,
.cl-icon-delete-fill:before,
.cl-icon-stop:before,
.cl-icon-play:before,
.cl-icon-more:before,
.cl-icon-back-top:before,
.cl-icon-location:before,
.cl-icon-keyboard-9:before,
.cl-icon-keyboard-26:before,
.cl-icon-customer-service:before,
.cl-icon-edit:before,
.cl-icon-scan:before,
.cl-icon-pay:before,
.cl-icon-warning-border:before,
.cl-icon-time:before,
.cl-icon-meh:before,
.cl-icon-cry:before,
.cl-icon-smile:before,
.cl-icon-refresh:before,
.cl-icon-plus-border:before,
.cl-icon-minus-border:before,
.cl-icon-check-border:before,
.cl-icon-close-border:before,
.cl-icon-help-border:before,
.cl-icon-caret-bottom:before,
.cl-icon-caret-top:before,
.cl-icon-toast-warning:before,
.cl-icon-notification:before,
.cl-icon-notification-fill:before,
.cl-icon-arrow-bottom:before,
.cl-icon-arrow-top:before,
.cl-icon-toast-waiting:before,
.cl-icon-toast-success:before,
.cl-icon-toast-error:before,
.cl-icon-arrow-left:before,
.cl-icon-arrow-right:before,
.cl-icon-plus:before,
.cl-icon-minus:before,
.cl-icon-check:before,
.cl-icon-close:before,
.cl-icon-search:before {
    font-family: "cl-iconfont";
    src: url("uni_modules/cool-ui/static/iconfont/iconfont.woff2") format("woff2"),
        url("uni_modules/cool-ui/static/iconfont/iconfont.woff") format("woff"),
        url("uni_modules/cool-ui/static/iconfont/iconfont.ttf") format("truetype");
    font-style: normal;
    line-height: 1;
}
[class*="cl-icon-"] {
@font-face {
    font-family: "cl-iconfont";
    src: url("uni_modules/cool-ui/static/iconfont/iconfont.woff2") format("woff2");
}
.cl-icon {
    font-family: "cl-iconfont" !important;
    font-size: inherit;
    font-style: normal;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    line-height: 1;
}
vite.config.ts
@@ -1,8 +1,35 @@
import uni from "@dcloudio/vite-plugin-uni"; // !此依赖不能安装
import fs from "fs";
import path from "path";
import { defineConfig } from "vite";
import { cool } from "@cool-vue/vite-plugin";
import { proxy } from "./config/proxy";
// 微信 WXSS 单行过长会编译失败。图标字体若同时内联 woff2/woff/ttf,会超过限制。
function shortenMpWeixinFonts() {
    return {
        name: "mp-weixin-shorten-fonts",
        enforce: "post" as const,
        closeBundle() {
            const dirs = ["unpackage/dist/dev/mp-weixin", "unpackage/dist/build/mp-weixin"];
            for (const dir of dirs) {
                const file = path.resolve(__dirname, dir, "app.wxss");
                if (!fs.existsSync(file)) continue;
                const css = fs.readFileSync(file, "utf8");
                const next = css.replace(
                    /src:\s*url\("data:font\/woff2;base64,[^"]+"\)\s*format\("woff2"\)\s*,\s*url\("data:font\/woff;base64,[^"]+"\)\s*format\("woff"\)\s*,\s*url\("data:font\/ttf;base64,[^"]+"\)\s*format\("truetype"\)/g,
                    (block) => {
                        const woff2 = block.match(
                            /url\("data:font\/woff2;base64,[^"]+"\)\s*format\("woff2"\)/
                        );
                        return woff2 ? `src: ${woff2[0]}` : block;
                    }
                );
                if (next !== css) fs.writeFileSync(file, next);
            }
        },
    };
}
function resolve(dir: string) {
    return path.resolve(__dirname, dir);
@@ -18,6 +45,7 @@
                type: "app",
                proxy,
            }),
            shortenMpWeixinFonts(),
        ],
        server: {
            port: 9900,