| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- <template>
- <cl-page>
- <cl-sticky>
- <cl-topbar fixed safe-area-top :title="`${$t('购物车 ({num})', { num: list.length })}`">
- <template #prepend>
- <!-- #ifdef MP -->
- <cl-text
- :pt="{
- className: 'ml-1'
- }"
- @tap="isDel = !isDel"
- >
- {{ isDel ? t("完成") : t("管理") }}
- </cl-text>
- <!-- #endif -->
- </template>
- <template #append>
- <!-- #ifndef MP -->
- <cl-text
- :pt="{
- className: 'mr-3'
- }"
- @tap="isDel = !isDel"
- >
- {{ isDel ? t("完成") : t("管理") }}
- </cl-text>
- <!-- #endif -->
- </template>
- </cl-topbar>
- </cl-sticky>
- <view class="p-3">
- <view class="p-3 rounded-xl bg-white dark:!bg-surface-800 mb-3">
- <cl-text
- :pt="{
- className: '!text-sm'
- }"
- >🔥 最新降价商品,限时优惠,抓紧抢购!</cl-text
- >
- </view>
- <cl-list-item
- v-for="(item, index) in list"
- :key="item.id"
- :pt="{
- className: parseClass([
- 'rounded-2xl ',
- [index == list.length - 1, 'mb-0', 'mb-3']
- ]),
- inner: {
- className: '!p-4'
- }
- }"
- swipeable
- >
- <view class="flex flex-row flex-1">
- <view class="flex flex-col mr-4 pt-[55rpx]" @tap="selectItem(item)">
- <cl-icon
- name="checkbox-circle-line"
- color="primary"
- :size="40"
- v-if="item.checked"
- ></cl-icon>
- <cl-icon name="checkbox-blank-circle-line" :size="40" v-else></cl-icon>
- </view>
- <cl-image :width="150" :height="150" :src="item.cover"></cl-image>
- <view class="flex flex-col ml-3 flex-1">
- <cl-text
- :pt="{
- className: 'mb-2 font-bold'
- }"
- >{{ item.name }}</cl-text
- >
- <view class="flex flex-row mb-2">
- <view
- class="bg-surface-100 dark:!bg-surface-700 rounded-md py-1 px-2 flex flex-row items-center"
- >
- <cl-text
- :pt="{
- className: '!text-xs'
- }"
- >{{ item.skuName }}</cl-text
- >
- <cl-icon name="arrow-down-s-line"></cl-icon>
- </view>
- </view>
- <view class="flex flex-row items-center mb-2">
- <cl-text
- :pt="{
- className: '!text-[22rpx] !text-red-500 mr-[1rpx]'
- }"
- >¥</cl-text
- >
- <cl-text
- :pt="{
- className: '!text-red-500 !text-[32rpx] mr-auto'
- }"
- >{{ item.price }}</cl-text
- >
- <view
- v-if="isDel"
- class="p-[8rpx] bg-red-500 rounded-lg"
- @tap="delItem(index)"
- >
- <cl-icon name="delete-bin-line" color="white" :size="24"></cl-icon>
- </view>
- <view class="flex" v-else>
- <cl-input-number
- v-model="item.count"
- :size="40"
- :min="1"
- :pt="{
- op: {
- plus: {
- className: '!rounded-full'
- },
- minus: {
- className: '!rounded-full'
- },
- icon: {
- size: 28
- }
- },
- value: {
- className: '!w-[60rpx] rounded-full !px-0',
- input: {
- className: '!text-[24rpx]'
- }
- }
- }"
- ></cl-input-number>
- </view>
- </view>
- <cl-text :size="22" color="error">比加入时降¥100</cl-text>
- <cl-text :size="22">满1件可换购0.5元商品</cl-text>
- </view>
- </view>
- <template #swipe-right>
- <cl-button
- type="error"
- :pt="{
- className: '!rounded-none h-full w-[160rpx]'
- }"
- @tap="delItem(index)"
- >{{ t("删除") }}</cl-button
- >
- </template>
- </cl-list-item>
- <cl-empty v-if="list.length == 0"></cl-empty>
- </view>
- <cl-footer>
- <view class="flex flex-row items-center h-[70rpx]">
- <cl-checkbox
- active-icon="checkbox-circle-line"
- inactive-icon="checkbox-blank-circle-line"
- :pt="{
- className: 'mr-auto'
- }"
- :size="28"
- v-model="selectAll"
- @change="onSelectAllChange"
- >{{ t("全选") }}</cl-checkbox
- >
- <template v-if="isDel">
- <cl-button
- type="error"
- :pt="{
- className: '!px-5'
- }"
- @tap="delAll"
- >
- {{ t("删除") }}
- </cl-button>
- </template>
- <template v-else>
- <view class="flex flex-col mr-3 items-end pt-1">
- <cl-text
- color="info"
- :pt="{
- className: '!text-xs'
- }"
- >{{ t("合计") }}</cl-text
- >
- <cl-text color="error" :value="totalPrice" type="amount"></cl-text>
- </view>
- <cl-button
- type="error"
- :pt="{
- className: '!px-8'
- }"
- @tap="toSettle"
- >
- {{ t("去结算") }}
- </cl-button>
- </template>
- </view>
- </cl-footer>
- </cl-page>
- </template>
- <script lang="ts" setup>
- import { parseClass, isEmpty } from "@/cool";
- import { $t, t } from "@/locale";
- import { useUi } from "@/uni_modules/cool-ui";
- import { computed, ref } from "vue";
- const ui = useUi();
- // 商品类型
- type Goods = {
- id: number;
- name: string;
- count: number;
- price: number;
- cover: string;
- skuName: string;
- checked: boolean;
- };
- // 商品列表
- const list = ref<Goods[]>([
- {
- id: 1,
- name: "Apple iPad",
- count: 1,
- price: 450,
- cover: "https://img.yzcdn.cn/vant/ipad.png",
- skuName: "深空灰色 128GB WLAN版",
- checked: true
- },
- {
- id: 2,
- name: "Samsung Galaxy S24",
- count: 2,
- price: 699,
- cover: "https://img.yzcdn.cn/vant/samsung.png",
- skuName: "曜石黑 12GB+256GB 官方标配",
- checked: false
- },
- {
- id: 3,
- name: "Sony WH-1000XM5",
- count: 1,
- price: 299,
- cover: "https://img.yzcdn.cn/vant/sony.png",
- skuName: "黑色 无线蓝牙 官方标配",
- checked: false
- },
- {
- id: 4,
- name: "小米手环8",
- count: 3,
- price: 49,
- cover: "https://img.yzcdn.cn/vant/xiaomi.png",
- skuName: "曜石黑 标准版 硅胶表带",
- checked: false
- },
- {
- id: 5,
- name: "Kindle Paperwhite",
- count: 1,
- price: 120,
- cover: "https://img.yzcdn.cn/vant/kindle.png",
- skuName: "黑色 8GB 官方标配",
- checked: false
- }
- ]);
- // 是否全选
- const selectAll = ref(false);
- /**
- * 选择/取消选择单个商品
- * @param item 需要操作的商品
- */
- function selectItem(item: Goods) {
- // 切换选中状态
- item.checked = !item.checked;
- // 判断是否所有商品都被选中,更新全选状态
- selectAll.value = list.value.every((item) => item.checked);
- }
- /**
- * 全选/取消全选
- * @param val 是否全选
- */
- function onSelectAllChange(val: boolean) {
- list.value.forEach((item, index, arr) => {
- // item.checked = val; // 这样写,在 android 上无效
- arr[index].checked = val;
- });
- }
- // 是否处于删除模式
- const isDel = ref(false);
- /**
- * 删除单个商品
- * @param index 商品索引
- */
- function delItem(index: number) {
- ui.showConfirm({
- title: t("温馨提示"),
- message: t("确定删除该商品吗?"),
- callback(action) {
- if (action === "confirm") {
- // 删除指定索引的商品
- list.value.splice(index, 1);
- ui.showToast({
- message: t("删除成功")
- });
- }
- }
- });
- }
- /**
- * 删除所有已选中的商品
- */
- function delAll() {
- const checked = list.value.filter((item) => item.checked);
- // 如果没有选中商品,提示用户
- if (isEmpty(checked)) {
- return ui.showToast({
- message: t("请先选择商品")
- });
- }
- ui.showConfirm({
- title: t("温馨提示"),
- message: t("确定删除选中的商品吗?"),
- callback(action) {
- if (action == "confirm") {
- // 只保留未选中的商品
- list.value = list.value.filter((item) => !item.checked);
- // 如果之前是全选,删除后取消全选状态
- if (selectAll.value) {
- selectAll.value = false;
- }
- ui.showToast({
- message: t("删除成功")
- });
- }
- }
- });
- }
- /**
- * 清空购物车
- */
- function clear() {
- list.value = [];
- selectAll.value = false;
- isDel.value = false;
- }
- /**
- * 计算已选中商品的总价
- */
- const totalPrice = computed(() => {
- return list.value
- .filter((item) => item.checked)
- .reduce((acc, item) => acc + item.price * item.count, 0);
- });
- /**
- * 结算操作
- */
- function toSettle() {
- // 如果没有选中商品,提示用户
- if (totalPrice.value <= 0) {
- return ui.showToast({
- message: t("请先选择商品")
- });
- }
- ui.showConfirm({
- title: t("温馨提示"),
- message: $t("您需支付 {price} 元,请确认支付", { price: totalPrice.value }),
- beforeClose(action, { showLoading, close }) {
- if (action == "confirm") {
- showLoading();
- setTimeout(() => {
- ui.showToast({
- message: t("支付成功")
- });
- close();
- }, 1000);
- } else {
- close();
- }
- }
- });
- }
- </script>
|