feat(recharge): add recharge package selection flow
- add new getRechargeOptions API endpoint in AigcApi - replace CustomAmountCard with RechargePackageList component - implement fetching and selection logic for recharge packages - update UI to use correct recharge data fields - add validation for selected recharge option
This commit is contained in:
@@ -5,16 +5,16 @@
|
|||||||
<view class="package-list">
|
<view class="package-list">
|
||||||
<view
|
<view
|
||||||
v-for="item in packages"
|
v-for="item in packages"
|
||||||
:key="item.id"
|
:key="getPackageKey(item)"
|
||||||
:class="['package-card', { 'is-selected': item.id === selectedId }]"
|
:class="['package-card', { 'is-selected': getPackageKey(item) === selectedKey }]"
|
||||||
@tap="emit('select', item)"
|
@tap="emit('select', item)"
|
||||||
>
|
>
|
||||||
<view class="package-copy">
|
<view class="package-copy">
|
||||||
<text class="package-points">{{ item.points }}积分</text>
|
<text class="package-points">{{ item.rechargePoints }}积分</text>
|
||||||
<text class="package-origin">原价 ¥{{ item.originalPrice }} · {{ item.discount }}</text>
|
<text class="package-origin">充值金额</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<text class="package-price">¥{{ formatPrice(item.price) }}</text>
|
<text class="package-price">¥{{ formatPrice(item.rechargeAmount) }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -26,7 +26,7 @@ defineProps({
|
|||||||
type: Array,
|
type: Array,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
selectedId: {
|
selectedKey: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "",
|
default: "",
|
||||||
},
|
},
|
||||||
@@ -35,6 +35,8 @@ defineProps({
|
|||||||
const emit = defineEmits(["select"]);
|
const emit = defineEmits(["select"]);
|
||||||
|
|
||||||
const formatPrice = (price) => Number(price).toLocaleString("zh-CN");
|
const formatPrice = (price) => Number(price).toLocaleString("zh-CN");
|
||||||
|
|
||||||
|
const getPackageKey = (item) => `${item?.rechargeAmount ?? ""}-${item?.rechargePoints ?? ""}`;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -17,8 +17,10 @@
|
|||||||
@ledger="handleOpenLedger"
|
@ledger="handleOpenLedger"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<CustomAmountCard
|
<RechargePackageList
|
||||||
v-model="customAmount"
|
:packages="rechargeOptions"
|
||||||
|
:selected-key="selectedRechargeKey"
|
||||||
|
@select="handleSelectRechargeOption"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<RechargeFooter
|
<RechargeFooter
|
||||||
@@ -32,21 +34,30 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
import { onShow } from "@dcloudio/uni-app";
|
import { onLoad, onShow } from "@dcloudio/uni-app";
|
||||||
import TopNavBar from "@/components/TopNavBar/index.vue";
|
import TopNavBar from "@/components/TopNavBar/index.vue";
|
||||||
import { useCurrentCredit } from "@/pages-aigc/hooks/useCurrentCredit.js";
|
import { useCurrentCredit } from "@/pages-aigc/hooks/useCurrentCredit.js";
|
||||||
import { rechargeCredit } from "@/request/api/AigcApi.js";
|
import { getRechargeOptions, rechargeCredit } from "@/request/api/AigcApi.js";
|
||||||
import BalanceCard from "./components/BalanceCard/index.vue";
|
import BalanceCard from "./components/BalanceCard/index.vue";
|
||||||
import CustomAmountCard from "./components/CustomAmountCard/index.vue";
|
|
||||||
import RechargeFooter from "./components/RechargeFooter/index.vue";
|
import RechargeFooter from "./components/RechargeFooter/index.vue";
|
||||||
|
import RechargePackageList from "./components/RechargePackageList/index.vue";
|
||||||
|
|
||||||
const { pointBalance: balancePoints, fetchCurrentCredit } = useCurrentCredit();
|
const { pointBalance: balancePoints, fetchCurrentCredit } = useCurrentCredit();
|
||||||
const customAmount = ref("1");
|
const rechargeOptions = ref([]);
|
||||||
|
const selectedRechargeOption = ref(null);
|
||||||
const paying = ref(false);
|
const paying = ref(false);
|
||||||
|
|
||||||
|
const getRechargeOptionKey = (option) => {
|
||||||
|
if (!option) return "";
|
||||||
|
|
||||||
|
return `${option.rechargeAmount ?? ""}-${option.rechargePoints ?? ""}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectedRechargeKey = computed(() => getRechargeOptionKey(selectedRechargeOption.value));
|
||||||
|
|
||||||
const payPrice = computed(() => {
|
const payPrice = computed(() => {
|
||||||
const amount = Number.parseInt(customAmount.value || "0", 10);
|
const amount = Number(selectedRechargeOption.value?.rechargeAmount);
|
||||||
return Number.isNaN(amount) ? 0 : amount;
|
return Number.isFinite(amount) ? amount : 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
const showToast = (title) => {
|
const showToast = (title) => {
|
||||||
@@ -56,6 +67,22 @@ const showToast = (title) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fetchRechargeOptions = async () => {
|
||||||
|
try {
|
||||||
|
const res = await getRechargeOptions();
|
||||||
|
if (res?.code === 0 && Array.isArray(res.data)) {
|
||||||
|
rechargeOptions.value = res.data;
|
||||||
|
selectedRechargeOption.value = res.data[0] || null;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("获取积分充值档位失败", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onLoad(() => {
|
||||||
|
fetchRechargeOptions();
|
||||||
|
});
|
||||||
|
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
fetchCurrentCredit();
|
fetchCurrentCredit();
|
||||||
});
|
});
|
||||||
@@ -74,6 +101,10 @@ const handleOpenLedger = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSelectRechargeOption = (option) => {
|
||||||
|
selectedRechargeOption.value = option;
|
||||||
|
};
|
||||||
|
|
||||||
const requestWechatPay = (payData) => {
|
const requestWechatPay = (payData) => {
|
||||||
const { nonceStr, packageVal, paySign, signType, timeStamp } = payData || {};
|
const { nonceStr, packageVal, paySign, signType, timeStamp } = payData || {};
|
||||||
|
|
||||||
@@ -107,9 +138,14 @@ const requestWechatPay = (payData) => {
|
|||||||
const handlePay = async () => {
|
const handlePay = async () => {
|
||||||
if (paying.value) return;
|
if (paying.value) return;
|
||||||
|
|
||||||
|
if (!selectedRechargeOption.value) {
|
||||||
|
showToast("请选择充值档位");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const rechargeAmount = payPrice.value;
|
const rechargeAmount = payPrice.value;
|
||||||
if (!Number.isInteger(rechargeAmount) || rechargeAmount <= 0) {
|
if (!Number.isInteger(rechargeAmount) || rechargeAmount <= 0) {
|
||||||
showToast("请输入正确的充值金额");
|
showToast("充值档位金额错误,请重试");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ function getCurrentCredit() {
|
|||||||
return request.get("/hotelBiz/credit/current", {});
|
return request.get("/hotelBiz/credit/current", {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRechargeOptions() {
|
||||||
|
return request.get("/hotelBiz/credit/recharge/options", {});
|
||||||
|
}
|
||||||
|
|
||||||
function rechargeCredit(args) {
|
function rechargeCredit(args) {
|
||||||
return request.post("/hotelBiz/credit/recharge", args);
|
return request.post("/hotelBiz/credit/recharge", args);
|
||||||
}
|
}
|
||||||
@@ -30,5 +34,6 @@ export {
|
|||||||
getAigcGeneratorTaskList,
|
getAigcGeneratorTaskList,
|
||||||
createAigcGeneratorTask,
|
createAigcGeneratorTask,
|
||||||
getCurrentCredit,
|
getCurrentCredit,
|
||||||
|
getRechargeOptions,
|
||||||
rechargeCredit,
|
rechargeCredit,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user