| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721 |
- <template>
- <cwg-page-wrapper class="create-page" :isHeaderFixed="true">
- <cwg-header :title="t('wallet.item52')" />
- <view id="custom_history" class="">
- <view class="main-content">
- <!-- 无任务列表提示 -->
- <view class="list-empty-state" v-if="!tableData || tableData.length === 0">
- <cwg-empty-state :title="t('UtaskList.item12')" />
- </view>
- <!-- 数据卡片展示 -->
- <view class="outer-card" v-for="(item, index) in tableData" :key="index"
- v-show="tableData && tableData.length > 0">
- <view class="data-cards">
- <!-- 第一行:总数据 -->
- <view class="total-data-row">
- <view class="data-card total-card">
- <view class="card-content">
- <view class="card-title">{{ t("DollarActivity.fieldDepositAmount") }}</view>
- <view class="card-value">{{ cell(item.depositAmount) }}</view>
- </view>
- </view>
- <view class="data-card total-card">
- <view class="card-content">
- <view class="card-title">{{ t("DollarActivity.fieldEndDate") }}</view>
- <view class="card-value">{{ cell(item.endDate) }}</view>
- </view>
- </view>
- <view class="data-card total-card">
- <view class="card-content">
- <view class="card-title">{{ t("DollarActivity.fieldApplyDepositAmount") }}</view>
- <view class="card-value">{{ cell(item.applyDepositAmount) }}</view>
- </view>
- </view>
- <view class="data-card total-card">
- <view class="card-content">
- <view class="card-title">{{ t("DollarActivity.fieldApplyGiveNum") }}</view>
- <view class="card-value">{{ cell(item.applyGiveNum) }}</view>
- </view>
- </view>
- <view class="data-card total-card">
- <view class="card-content">
- <view class="card-title">{{ t("Label.State") }}</view>
- <view class="card-value" :style="statusStyle(item.status)">
- {{ statusText(item.status) }}
- </view>
- </view>
- </view>
- </view>
- <!-- 操作按钮行 -->
- <view class="card-actions">
- <view class="btn btn-outline-secondary btn-sm" @click="openApplyRecordDialog(item)">
- {{ t("DollarActivity.applyRecord") }}
- </view>
- <view v-if="Number(item.status) === 1" class="btn btn-dark waves-effect waves-light"
- :loading="cancelLoadingId === item.id" @click="confirmCancelDollarActivity(item)">
- {{ t("Btn.Cancel") }}
- </view>
- <!-- <view v-if="showDollarClaimRewardButton(item)" class="btn btn-dark waves-effect waves-light"
- @click="openClaimDialog(item)"> -->
- <view class="btn btn-dark waves-effect waves-light" @click="openClaimDialog(item)">
- {{ t("DollarActivity.claimReward") }}
- </view>
- </view>
- </view>
- </view>
- </view>
- </view>
- <!-- 领取奖励对话框 -->
- <cwg-popup v-model:visible="dialogClaimVisible" type="center" :mask-click="false" :showFooters="true"
- :showClose="false" :title="t('DollarActivity.dialogClaimTitle')">
- <view class="dialog-popup1">
- <cwg-combox v-model:value="selectedRuleId" :clearable="false" :options="ruleOptionsList"
- :placeholder="t('UtaskList.item19')" @change="handleGiftChange" />
- <template #footer>
- <button class="btn btn-danger btn-sm waves-effect waves-light" @click="closeApplyRecordDialog">{{
- t('Btn.Confirm') }}</button>
- </template>
- </view>
- <template #footer>
- <button class="btn btn-outline-secondary" @click="closeClaimDialog">{{ t("Btn.Cancel") }}</button>
- <button class="btn btn-dark waves-effect waves-light btn-primary" :loading="applySubmitting"
- :disabled="selectedRuleId === null || selectedRuleId === ''" @click="confirmClaimReward">{{
- t("Btn.Confirm") }}</button>
- </template>
- </cwg-popup>
- <!-- 申请记录对话框 -->
- <cwg-popup v-model:visible="dialogApplyRecordVisible" type="center" :mask-click="false" :showFooters="true"
- :width="'900px'" :showClose="false" :title="t('DollarActivity.applyRecord')">
- <view class="popup-content">
- <view class="dialog-body">
- <uni-loading v-if="applyRecordList.length === 0 && applyRecordLoading"
- v-loading="applyRecordLoading" />
- <view class="record-table" v-if="applyRecordList.length > 0">
- <view class="table-header">
- <text class="col-deposit">{{ t("DollarActivity.recordDepositAmount") }}</text>
- <text class="col-reward">{{ t("DollarActivity.recordRewardAmount") }}</text>
- <text class="col-standard">{{ t("DollarActivity.fieldStandardVolume") }}</text>
- <text class="col-ecn">{{ t("DollarActivity.fieldEcnVolume") }}</text>
- <text class="col-cent">{{ t("DollarActivity.fieldCentVolume") }}</text>
- <text class="col-time">{{ t("DollarActivity.fieldApplyTime") }}</text>
- </view>
- <!-- 表格内容 -->
- <view class="table-body">
- <view class="table-row" v-for="(record, idx) in applyRecordList" :key="idx">
- <text class="col-deposit">{{ cell(record.depositAmount) }}</text>
- <text class="col-reward">{{ cell(record.rewardAmount) }}</text>
- <text class="col-standard">{{ cell(record.standardVolume) }}</text>
- <text class="col-ecn">{{ cell(record.ecnVolume) }}</text>
- <text class="col-cent">{{ cell(record.centVolume) }}</text>
- <text class="col-time">{{ cell(record.addTime) }}</text>
- </view>
- </view>
- </view>
- <view v-if="applyRecordList.length === 0 && !applyRecordLoading" class="apply-record-empty">
- <cwg-empty-state />
- </view>
- </view>
- </view>
- <template #footer>
- <button class="btn btn-dark waves-effect waves-light" @click="closeApplyRecordDialog">{{
- t('Btn.Confirm') }}</button>
- </template>
- </cwg-popup>
- <cwg-confirm-popup />
- </cwg-page-wrapper>
- </template>
- <script setup lang="ts">
- import { ref, computed, onMounted } from 'vue'
- import { useI18n } from 'vue-i18n'
- import { activityApi } from "@/service/activity"
- import Config from "@/config/index"
- import useUserStore from "@/stores/use-user-store";
- import { useConfirm } from '@/hooks/useConfirm'
- const userStore = useUserStore();
- const confirm = useConfirm()
- const { t } = useI18n()
- let { Code } = Config
- // ---------- 响应式数据 ----------
- const flag = ref(false)
- const pictLoading = ref(false)
- const tableData = ref<any[]>([])
- // 领取奖励弹窗相关
- const claimDialog = ref<any>(null)
- const dialogClaimVisible = ref(false)
- const claimTaskId = ref<any>(null)
- const ruleOptions = ref<any[]>([])
- const selectedRuleId = ref<any>(null)
- const selectedRuleIndex = ref(-1)
- const ruleLoading = ref(false)
- const applySubmitting = ref(false)
- // 取消任务相关
- const cancelLoadingId = ref<any>(null)
- const ruleOptionsList = computed(() => {
- return ruleOptions.value.map((opt: any) => ({
- key: ruleOptionKey(opt),
- text: ruleOptionLabel(opt),
- value: ruleOptionValue(opt),
- disable: isRuleOptionDisabled(opt),
- }))
- })
- // 申请记录弹窗相关
- const applyRecordDialog = ref<any>(null)
- const dialogApplyRecordVisible = ref(false)
- const applyRecordLoading = ref(false)
- const applyRecordList = ref<any[]>([])
- const applyRecordTaskId = ref<any>(null)
- // ---------- 方法 ----------
- const cell = (v: any) => {
- if (v === null || v === undefined || v === "") {
- return "--"
- }
- return v
- }
- const formatApplyRecordCell = (row: any, column: any, cellValue: any) => {
- return cell(cellValue)
- }
- const statusText = (status: any) => {
- const s = Number(status)
- if (s === 1) {
- return t("DollarActivity.statusInTask")
- }
- if (s === 2) {
- return t("DollarActivity.statusEnded")
- }
- if (s === 3) {
- return t("DollarActivity.statusCancelled")
- }
- return "--"
- }
- const statusStyle = (status: any) => {
- const s = Number(status)
- if (s === 1) {
- return { color: "#52c41a" }
- }
- if (s === 2) {
- return { color: "#eb3f57" }
- }
- if (s === 3) {
- return { color: "#8c8c8c" }
- }
- return { color: "#333" }
- }
- /** 已结束且剩余可申请次数不为 0 时显示领取奖励 */
- const showDollarClaimRewardButton = (item: any) => {
- if (Number(item.status) !== 2) {
- return false
- }
- const n = item.applyGiveNum
- if (n === null || n === undefined) {
- return true
- }
- return Number(n) !== 0
- }
- const backActivity = () => {
- uni.navigateBack()
- }
- // picker 显示标签
- const rulePickerLabel = (opt: any) => {
- if (!opt) return ''
- const dep = cell(opt.depositAmount)
- const rew = cell(opt.rewardAmount)
- return `${t("DollarActivity.fieldDepositAmount")}: ${dep} - ${t("DollarActivity.fieldRewardAmount")}: ${rew}`
- }
- // 处理 picker 选择变化
- const onRuleChange = (e: any) => {
- const idx = e.detail.value
- if (idx !== undefined && ruleOptions.value[idx]) {
- selectedRuleIndex.value = idx
- selectedRuleId.value = ruleOptionValue(ruleOptions.value[idx])
- }
- }
- const ruleOptionValue = (opt: any) => {
- if (opt == null) {
- return null
- }
- const v = opt.id != null ? opt.id : opt.ruleId
- return v
- }
- const ruleOptionKey = (opt: any) => {
- const v = ruleOptionValue(opt)
- return v != null ? String(v) : Math.random()
- }
- const ruleOptionLabel = (opt: any) => {
- const dep = cell(opt.depositAmount)
- const rew = cell(opt.rewardAmount)
- return `${t("DollarActivity.fieldDepositAmount")}: ${dep} - ${t("DollarActivity.fieldRewardAmount")}: ${rew}`
- }
- /** display: 0 不可选(置灰),1 可选;未返回 display 时默认可选 */
- const isRuleOptionDisabled = (opt: any) => {
- if (opt == null || opt.display === undefined || opt.display === null) {
- return false
- }
- return Number(opt.display) !== 1
- }
- const normalizeRuleList = (data: any) => {
- if (Array.isArray(data)) {
- return data
- }
- if (data && typeof data === "object") {
- if (Array.isArray(data.list)) {
- return data.list
- }
- if (Array.isArray(data.rules)) {
- return data.rules
- }
- }
- return []
- }
- const normalizeGiveRecordList = (data: any) => {
- if (Array.isArray(data)) {
- return data
- }
- if (data && typeof data === "object") {
- if (Array.isArray(data.list)) {
- return data.list
- }
- if (Array.isArray(data.records)) {
- return data.records
- }
- }
- return []
- }
- const openApplyRecordDialog = (item: any) => {
- applyRecordTaskId.value = item.id
- applyRecordList.value = []
- dialogApplyRecordVisible.value = true
- loadApplyRecordList()
- }
- const closeApplyRecordDialog = () => {
- dialogApplyRecordVisible.value = false
- onApplyRecordDialogClosed()
- }
- const onApplyRecordDialogClosed = () => {
- applyRecordTaskId.value = null
- applyRecordList.value = []
- }
- const loadApplyRecordList = async () => {
- if (applyRecordTaskId.value == null || applyRecordTaskId.value === "") {
- return
- }
- applyRecordLoading.value = true
- try {
- const res = await activityApi.ActivityDollarGiveRecord({
- id: applyRecordTaskId.value,
- })
- if (res.code == Code.StatusOK) {
- applyRecordList.value = normalizeGiveRecordList(res.data)
- } else {
- uni.showToast({ title: res.msg, icon: "none" })
- applyRecordList.value = []
- }
- } catch {
- uni.showToast({ title: t("Msg.Fail"), icon: "none" })
- applyRecordList.value = []
- } finally {
- applyRecordLoading.value = false
- }
- }
- const confirmCancelDollarActivity = async (item: any) => {
- try {
- await confirm({
- title: t("Msg.SystemPrompt"),
- content: t("DollarActivity.confirmCancel"),
- confirmText: t("Btn.Confirm"),
- cancelText: t("Btn.Cancel"),
- })
- } catch {
- return
- }
- cancelLoadingId.value = item.id
- try {
- const res = await activityApi.ActivityDollarCancel({ id: item.id })
- if (res.code == Code.StatusOK) {
- uni.showToast({ title: res.msg || t("Msg.Success"), icon: "success" })
- await searchFunc()
- } else {
- uni.showToast({ title: res.msg, icon: "none" })
- }
- } catch {
- uni.showToast({ title: t("Msg.Fail"), icon: "none" })
- } finally {
- cancelLoadingId.value = null
- }
- }
- const openClaimDialog = async (item: any) => {
- claimTaskId.value = item.id
- selectedRuleId.value = null
- selectedRuleIndex.value = -1
- ruleOptions.value = []
- dialogClaimVisible.value = true
- await loadDollarRules()
- }
- const closeClaimDialog = () => {
- dialogClaimVisible.value = false
- onClaimDialogClosed()
- }
- const onClaimDialogClosed = () => {
- claimTaskId.value = null
- ruleOptions.value = []
- selectedRuleId.value = null
- selectedRuleIndex.value = -1
- }
- const loadDollarRules = async () => {
- if (claimTaskId.value == null || claimTaskId.value === "") {
- return
- }
- ruleLoading.value = true
- try {
- const res = await activityApi.ActivityDollarRule({ id: claimTaskId.value })
- if (res.code == Code.StatusOK) {
- ruleOptions.value = normalizeRuleList(res.data)
- // 为每个选项添加显示标签
- ruleOptions.value.forEach((opt: any) => {
- opt.displayLabel = ruleOptionLabel(opt)
- })
- if (ruleOptions.value.length === 0) {
- uni.showToast({ title: res.msg || t("DollarActivity.emptyRuleList"), icon: "none" })
- }
- } else {
- uni.showToast({ title: res.msg, icon: "none" })
- }
- } catch {
- uni.showToast({ title: t("Msg.Fail"), icon: "none" })
- } finally {
- ruleLoading.value = false
- }
- }
- const confirmClaimReward = async () => {
- if (selectedRuleId.value === null || selectedRuleId.value === "" || claimTaskId.value == null) {
- uni.showToast({ title: t("DollarActivity.selectRulePlaceholder"), icon: "none" })
- return
- }
- applySubmitting.value = true
- try {
- const res = await activityApi.ActivityDollarApply({
- id: claimTaskId.value,
- ruleId: selectedRuleId.value,
- })
- if (res.code == Code.StatusOK) {
- uni.showToast({ title: res.msg || t("Msg.Success"), icon: "success" })
- closeClaimDialog()
- await searchFunc()
- } else {
- uni.showToast({ title: res.msg, icon: "none" })
- }
- } catch {
- uni.showToast({ title: t("Msg.Fail"), icon: "none" })
- } finally {
- applySubmitting.value = false
- }
- }
- const searchFunc = async () => {
- if (flag.value) {
- return
- }
- flag.value = true
- pictLoading.value = true
- let res = await activityApi.ActivityDollarSearchList()
- if (res.code == Code.StatusOK) {
- tableData.value = Array.isArray(res.data) ? res.data : []
- } else {
- uni.showToast({ title: res.msg, icon: "none" })
- }
- pictLoading.value = false
- flag.value = false
- }
- // ---------- 生命周期 ----------
- onMounted(() => {
- searchFunc()
- })
- </script>
- <style lang="scss" scoped>
- @import "@/uni.scss";
- #custom_history {
- width: 100%;
- height: 100%;
- .main-content {
- width: 100%;
- height: calc(100% - 50px);
- padding: px2rpx(20);
- box-sizing: border-box;
- overflow: hidden;
- overflow-y: auto;
- }
- .outer-card {
- background: #ffffff;
- border-radius: px2rpx(16);
- padding: px2rpx(24);
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
- border: 1px solid #f0f0f0;
- margin-bottom: px2rpx(24);
- }
- .data-cards {
- .card-actions {
- margin-top: px2rpx(16);
- padding-top: px2rpx(12);
- border-top: 1px solid #f0f0f0;
- display: flex;
- flex-wrap: wrap;
- justify-content: center;
- align-items: center;
- gap: px2rpx(20);
- .btn {
- padding: px2rpx(8) px2rpx(16);
- font-size: px2rpx(14);
- border-radius: px2rpx(6);
- }
- }
- .total-data-row {
- display: grid;
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
- gap: px2rpx(16);
- }
- .data-card {
- background: #fafafa;
- border-radius: px2rpx(12);
- padding: px2rpx(20) px2rpx(16);
- border: 1px solid #f0f0f0;
- text-align: center;
- .card-title {
- font-size: px2rpx(14);
- color: #666;
- margin-bottom: px2rpx(10);
- font-weight: 500;
- }
- .card-value {
- font-size: px2rpx(18);
- font-weight: 600;
- color: #333;
- line-height: 1.3;
- word-break: break-word;
- }
- }
- }
- @media (max-width: 768px) {
- .data-cards .total-data-row {
- grid-template-columns: 1fr;
- }
- }
- }
- .dialog-body {
- min-height: px2rpx(120);
- max-height: 60vh;
- overflow-y: auto;
- .picker-view {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: px2rpx(12) px2rpx(16);
- border: 1px solid #dcdfe6;
- border-radius: px2rpx(8);
- .placeholder-text {
- color: #c0c4cc;
- }
- .picker-arrow {
- color: #909399;
- font-size: px2rpx(14);
- }
- }
- .record-table {
- width: 100%;
- overflow-x: auto;
- font-size: px2rpx(14);
- .table-header,
- .table-row {
- display: flex;
- min-width: 600px;
- text-align: center;
- padding: px2rpx(20) px2rpx(8);
- border-bottom: 1px solid #ebeef5;
- }
- .table-header {
- background: #f5f7fa;
- font-weight: 600;
- color: #606266;
- }
- .col-deposit,
- .col-reward,
- .col-standard,
- .col-ecn,
- .col-cent,
- .col-time {
- flex: 1;
- word-break: break-word;
- }
- }
- .apply-record-empty {
- text-align: center;
- color: #999;
- padding: px2rpx(24) 0;
- font-size: px2rpx(14);
- }
- }
- // 弹窗样式
- .dialog-popup {
- background: #ffffff;
- border-radius: px2rpx(16);
- width: 85%;
- max-width: 480px;
- &.dialog-large {
- max-width: 90%;
- width: 90%;
- @media (min-width: 768px) {
- max-width: 900px;
- width: 900px;
- }
- }
- .dialog-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: px2rpx(20) px2rpx(24);
- border-bottom: 1px solid #f0f0f0;
- .dialog-title {
- font-size: px2rpx(18);
- font-weight: 600;
- color: #333;
- }
- .dialog-close {
- width: px2rpx(32);
- height: px2rpx(32);
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- .close-icon {
- font-size: px2rpx(20);
- color: #999;
- }
- }
- }
- .dialog-footer {
- display: flex;
- justify-content: flex-end;
- gap: px2rpx(12);
- padding: px2rpx(16) px2rpx(24);
- border-top: 1px solid #f0f0f0;
- button {
- padding: px2rpx(8) px2rpx(20);
- font-size: px2rpx(14);
- border-radius: px2rpx(6);
- }
- }
- }
- .dialog-popup1 {
- height: 20vh;
- max-height: 80vh;
- }
- // loading 状态
- [v-loading] {
- position: relative;
- }
- // 按钮样式
- .btn {
- border: none;
- border-radius: px2rpx(6);
- cursor: pointer;
- transition: all 0.3s ease;
- }
- .btn-primary {
- &[disabled] {
- background-color: #f56c6c;
- cursor: not-allowed;
- color: var(--bs-body-bg);
- }
- }
- .btn-danger {
- background-color: #f56c6c;
- color: white;
- &:active {
- background-color: #e85c5c;
- }
- }
- .btn-outline-secondary {
- background-color: transparent;
- border: 1px solid #dcdfe6;
- color: #606266;
- &:active {
- background-color: #f5f7fa;
- }
- }
- </style>
|