zhb 2 周之前
父節點
當前提交
e6c774d3b2

+ 1 - 1
components/cwg-image.vue

@@ -1,5 +1,5 @@
 <template>
-    <image :src="props.src" mode="aspectFill" class="preview-image" @click="handlePreviewImage" />
+    <image :src="props.src" mode="widthFix" class="preview-image" @click="handlePreviewImage" />
 </template>
 
 <script setup>

+ 8 - 8
locale/cn.json

@@ -5932,13 +5932,13 @@
     "fieldRewardAmount": "奖励金额",
     "emptyRuleList": "暂无可选奖励档位",
     "confirmCancel": "是否取消活动?",
-    "applyRecordsBtn": "申请记录",
-    "dialogApplyRewardRecordsTitle": "申请奖励记录",
-    "giveColumnDepositAmount": "入金量",
-    "giveColumnRewardAmount": "奖励金",
-    "giveColumnStandardVolume": "标准账户",
-    "giveColumnEcnVolume": "ECN账户",
-    "giveColumnCentVolume": "美分账户",
-    "giveColumnAddTime": "申请时间"
+    "activityDetails": "活动详情",
+    "applyRecord": "申请记录",
+    "recordDepositAmount": "入金量",
+    "recordRewardAmount": "奖励金",
+    "fieldStandardVolume": "标准账户",
+    "fieldEcnVolume": "ECN账户",
+    "fieldCentVolume": "美分账户",
+    "fieldApplyTime": "申请时间"
   }
 }

+ 8 - 8
locale/en.json

@@ -6222,13 +6222,13 @@
     "fieldRewardAmount": "Reward amount",
     "emptyRuleList": "No reward tiers available",
     "confirmCancel": "Cancel this activity?",
-    "applyRecordsBtn": "Application records",
-    "dialogApplyRewardRecordsTitle": "Reward application records",
-    "giveColumnDepositAmount": "Deposit volume",
-    "giveColumnRewardAmount": "Reward",
-    "giveColumnStandardVolume": "Standard account",
-    "giveColumnEcnVolume": "ECN account",
-    "giveColumnCentVolume": "Cent account",
-    "giveColumnAddTime": "Application time"
+    "activityDetails": "Activity details",
+    "applyRecord": "Application records",
+    "recordDepositAmount": "Deposit volume",
+    "recordRewardAmount": "Reward",
+    "fieldStandardVolume": "Standard account",
+    "fieldEcnVolume": "ECN account",
+    "fieldCentVolume": "Cent account",
+    "fieldApplyTime": "Application time"
   }
 }

+ 8 - 0
pages.json

@@ -117,6 +117,14 @@
         "navigationStyle": "custom"
       }
     },
+    {
+      "path": "pages/activities/dollar-list",
+      "style": {
+        "navigationBarTitleText": "",
+        "backgroundColor": "transparent",
+        "navigationStyle": "custom"
+      }
+    },
     {
       "path": "pages/activities/surplus-list",
       "style": {

+ 57 - 4
pages/activities/content.vue

@@ -16,10 +16,11 @@
                     !ActivitySingle23jnhcj &&
                     !ActivitySingleNewList &&
                     !ActivitySingleNoWorries &&
+                    !ActivitySingleDollar &&
                     !ActivitySingleNewYear24">
                     <view class="img">
                         <cwg-image :lazy="false"
-                            :src="imgUrl + (singleData.activityImage ? singleData.activityImage : singleData.coverImage)">
+                            :src="imgUrl + (singleData.activityImage ? singleData.activityImage : singleData.coverImage)" >
                         </cwg-image>
                     </view>
                     <cwg-html :richHtml="singleData.content" />
@@ -31,6 +32,20 @@
                     </view>
                     <cwg-html :richHtml="singleData.content" />
                 </view>
+                <div class="content crm-border-radius dollar-activity-content" v-if="ActivitySingleDollar">
+                    <div class="img" v-if="dollarCoverDisplay">
+                        <cwg-image style="width: 500px;" :src="dollarCoverDisplay">
+                        </cwg-image>
+                    </div>
+                    <h4 v-if="dollarDetail && dollarDetail.title"
+                        style="text-align: center; font-size: 18px; margin-bottom: 15px">
+                        {{ dollarDetail.title }}
+                    </h4>
+                    <div v-if="dollarDetail && dollarDetail.subTitle" style="font-size: 14px; margin-bottom: 15px">
+                        {{ dollarDetail.subTitle }}
+                    </div>
+                    <div class="dollar-detail-body" v-html="dollarDetail && dollarDetail.content"></div>
+                </div>
                 <view class="content crm-border-radius" v-if="ActivitySingle20">
                     <view v-if="country == 'CN'">
                         <view>
@@ -1050,9 +1065,20 @@ const active = ref('')
 const imgUrl = Host05
 const imgContent = ref('https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg')
 const singleData = ref<any>([])
-
+const dollarCoverDisplay = computed(() => {
+    const d = dollarDetail.value;
+    if (!d || !d.coverUrl) {
+        return "";
+    }
+    const u = String(d.coverUrl);
+    if (/^https?:\/\//i.test(u)) {
+        return u;
+    }
+    return imgUrl + u;
+})
 // 活动类型标志
 const ActivitySingle20 = ref(false)
+const ActivitySingleDollar = ref(false)
 const ActivitySingle23 = ref(false)
 const ActivitySingle23jx = ref(false)
 const ActivitySingle23jxVip = ref(false)
@@ -1394,6 +1420,9 @@ onLoad((query) => {
     } else if (active.value == 'newList') {
         ActivitySingleNewList.value = true
         getSingle1(myId.value)
+    } else if (active.value == 'dollar') {
+        ActivitySingleDollar.value = true;
+        loadDollarActivity();
     } else {
         getSingle(myId.value)
         ActivitySingle20.value = false
@@ -1411,7 +1440,22 @@ onLoad((query) => {
         ActivitySingleNewYear24.value = false
     }
 })
-
+const dollarDetail = ref(null)
+const loadDollarActivity = async () => {
+    let res = await activityApi.ActivityShowsInfo({});
+    if (res.code == Code.StatusOK) {
+        const d = res.data && res.data.dollar;
+        if (!d || Number(d.show) !== 1) {
+            uni.showToast({ title: t('Msg.SearchFail'), icon: 'none' })
+            backActivity();
+            return;
+        }
+        dollarDetail.value = d;
+    } else {
+        uni.showToast({ title: res.msg, icon: 'none' })
+        backActivity();
+    }
+}
 // 清理定时器
 onUnmounted(() => {
     clearInterval(interval1.value)
@@ -1434,12 +1478,21 @@ onUnmounted(() => {
     .img {
         display: flex;
         align-items: center;
-        justify-content: center;
         margin-bottom: 20px;
 
     }
 }
 
+.dollar-activity-content {
+    .dollar-detail-body {
+        word-break: break-word;
+        font-size: 14px;
+        :deep(p) {
+            margin: 0 0 6px;
+        }
+    }
+}
+
 .toDocumentary {
     text-decoration: underline;
     color: blue;

+ 721 - 0
pages/activities/dollar-list.vue

@@ -0,0 +1,721 @@
+<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>

+ 135 - 83
pages/activities/index.vue

@@ -181,56 +181,59 @@
                         </view>
                     </view>
 
-                    <!-- 美金活动 dollarActivity-->
-<!--                    <view class="col-12 m-b30" v-if="true">
+
+
+                    <!-- 美金活动(/custom/activity/shows/info dollar) -->
+                    <view class="col-12 m-b30" v-if="dollarActivity">
                         <view class="card card-action action-elevate action-border-primary">
                             <view class="row g-0">
                                 <view class="col-md-3">
-                                    <view class="card-header border-0 p-0 m-2 position-relative overflow-hidden" >
-                                        <image v-if="dollarCoverSrc" :src="dollarCoverSrc" alt="" class="img-fluid rounded"
-                                            mode="widthFix" />
+                                    <view class="card-header border-0 p-0 m-2 position-relative overflow-hidden">
+
+                                        <image v-if="dollarCoverSrc" :src="dollarCoverSrc" alt=""
+                                            class="img-fluid rounded" mode="widthFix" />
+                                        <view
+                                            class="position-absolute action-visible top-0 start-0 h-100 w-100 bg-opacity-50 rounded d-flex align-items-center justify-content-center">
+                                            <view @click="openDollarParticipate"
+                                                class="btn btn-icon btn-lg btn-secondary rounded-circle waves-effect waves-light">
+                                                →</view>
+                                        </view>
                                     </view>
                                 </view>
                                 <view class="col-md-8 py-3 d-flex flex-column">
                                     <view class="card-body px-3 py-2">
-                                        <p v-if="dollarActivity.title" class="crm-one-font lh-sm" >
-                                          {{dollarActivity.title}}
-                                        </p>
-                                      <p v-if="dollarActivity.subTitle" class="crm-one-font lh-sm" >
-                                        {{dollarActivity.subTitle}}
-                                      </p>
-                                      <p v-else-if="dollarActivity.content" class="crm-one-font lh-sm dollar-activity-html" v-html="dollarActivity.content">
-                                      </p>
+                                        <h4> <text class="text-dark crm-one-font" v-if="dollarActivity.title">{{
+                                            dollarActivity.title }}</text>
+                                        </h4>
+                                        <p class="crm-one-font lh-sm" v-if="dollarActivity.subTitle">
+                                            {{ dollarActivity.subTitle }}</p>
                                         <view class="d-flex flex-wrap gap-2">
                                             <view
                                                 :class="['btn btn-dark waves-effect waves-light', dollarParticipateEnabled ? 'btn-danger' : 'disabled']"
-                                                @click="openDollarParticipate()">
+                                                @click="openDollarParticipate">
                                                 <text v-t="'DollarActivity.participate'"></text>
                                             </view>
-                                          <view
-                                            @click="goDollarTaskList()"
-                                            :class="['btn btn-outline-dark1 waves-effect waves-light' ]"
-                                          >
-                                            <text v-t="'wallet.item14'"></text>
-                                          </view>
-                                          <view
-                                            @click="goDollarActivityDetail()"
-                                            :class="['btn btn-outline-dark1 waves-effect waves-light' ]"
-                                          >
-                                            <text v-t="'Custom.Activity.Single'"></text>
-                                          </view>
+                                            <view class="btn btn-outline-dark1 waves-effect waves-light"
+                                                @click="goDollarTaskList">
+                                                <text v-t="'wallet.item14'"></text>
+                                            </view>
+                                            <view v-if="dollarActivity.content"
+                                                class="btn btn-outline-dark1 waves-effect waves-light"
+                                                @click="goDollarActivityDetail">
+                                                <text v-t="'DollarActivity.activityDetails'"></text>
+                                            </view>
                                         </view>
                                     </view>
                                 </view>
                             </view>
                         </view>
-                    </view>-->
+                    </view>
                     <!-- 无忧交易 -->
                     <view class="col-12 m-b30" v-if="tableDataNoWorriesFlag">
                         <view class="card card-action action-elevate action-border-primary">
                             <view class="row g-0">
                                 <view class="col-md-3">
-                                    <view class="card-header border-0 p-0 m-2 position-relative overflow-hidden" >
+                                    <view class="card-header border-0 p-0 m-2 position-relative overflow-hidden">
                                         <image src="/static/images/jihua.png" alt="" class="img-fluid rounded"
                                             mode="widthFix" />
                                         <view
@@ -243,13 +246,14 @@
                                 </view>
                                 <view class="col-md-8 py-3 d-flex flex-column">
                                     <view class="card-body px-3 py-2">
-                                        <h4 @click="toSingle('NoWorries')"> <text class="text-dark crm-one-font" v-t="'news_add_field1.activitiesNoWorries.item1'"></text>
+                                        <h4 @click="toSingle('NoWorries')"> <text class="text-dark crm-one-font"
+                                                v-t="'news_add_field1.activitiesNoWorries.item1'"></text>
                                         </h4>
-                                        <p class="crm-one-font lh-sm" v-t="'news_add_field1.activitiesNoWorries.item2'"></p>
+                                        <p class="crm-one-font lh-sm" v-t="'news_add_field1.activitiesNoWorries.item2'">
+                                        </p>
                                         <view class="d-flex flex-wrap gap-2">
-                                            <view
-                                              v-if="typeof tableDataNoWorries == 'boolean' && tableDataNoWorries"
-                                                :class="['btn btn-dark waves-effect waves-light',  'btn-danger' ]"
+                                            <view v-if="typeof tableDataNoWorries == 'boolean' && tableDataNoWorries"
+                                                :class="['btn btn-dark waves-effect waves-light', 'btn-danger']"
                                                 @click="toApplyNoWorriesOpen()">
                                                 <text v-t="'news_add_field1.activitiesNoWorries.item3'"></text>
                                             </view>
@@ -258,12 +262,10 @@
                                                 @click="toRealizationNoWorries()">
                                                 <text v-t="'news_add_field1.activitiesNoWorries.item4'"></text>
                                             </view>
-                                          <view
-                                            @click="toSingle('NoWorries')"
-                                            :class="['btn btn-outline-dark1 waves-effect waves-light' ]"
-                                          >
-                                            <text v-t="'news_add_field1.activitiesNoWorries.item5'"></text>
-                                          </view>
+                                            <view @click="toSingle('NoWorries')"
+                                                :class="['btn btn-outline-dark1 waves-effect waves-light']">
+                                                <text v-t="'news_add_field1.activitiesNoWorries.item5'"></text>
+                                            </view>
                                         </view>
                                     </view>
                                 </view>
@@ -625,7 +627,7 @@
                 <button type="primary" @click="toApplyNoWorries">{{
                     t('news_add_field1.activitiesNoWorries.item6_1') }}</button>
                 <button @click="toApplyNoWorriesCancel">{{ t('news_add_field1.activitiesNoWorries.item6_2')
-                    }}</button>
+                }}</button>
             </template>
         </cwg-popup>
 
@@ -640,7 +642,7 @@
                 <button type="primary" @click="realizationNoWorries">{{
                     t('news_add_field1.activitiesNoWorries.item6_1') }}</button>
                 <button @click="dialogNoWorries = false">{{ t('news_add_field1.activitiesNoWorries.item6_2')
-                }}</button>
+                    }}</button>
             </template>
         </cwg-popup>
 
@@ -655,7 +657,7 @@
                 <button type="primary" @click="dialogNoWorriesApply = false">{{
                     t('news_add_field1.activitiesNoWorries.item6_1') }}</button>
                 <button @click="dialogNoWorriesApply = false">{{ t('news_add_field1.activitiesNoWorries.item6_2')
-                    }}</button>
+                }}</button>
             </template>
         </cwg-popup>
 
@@ -680,7 +682,7 @@
             </view>
             <template #footer>
                 <button type="primary" @click="calculateIncome">{{ t('news_add_field1.NewYear24.item8_1')
-                }}</button>
+                    }}</button>
                 <button @click="openCalculatorFlag = false">{{ t('news_add_field1.NewYear24.item8_2') }}</button>
             </template>
         </cwg-popup>
@@ -1045,49 +1047,50 @@ const isSupportedCountry = computed(() => {
 })
 
 const dollarActivity = computed(() => {
-  const info = activityShowsInfo.value;
-  if (!info || !info.dollar) {
-    return null;
-  }
-  const d = info.dollar;
-  if (Number(d.show) !== 1) {
-    return null;
-  }
-  return d;
+    const info = activityShowsInfo.value;
+    if (!info || !info.dollar) {
+        return null;
+    }
+    const d = info.dollar;
+    if (Number(d.show) !== 1) {
+        return null;
+    }
+    return d;
 })
 
 const dollarCoverSrc = computed(() => {
-  const d = dollarActivity.value;
-  if (!d || !d.coverUrl) {
-    return "";
-  }
-  const u = String(d.coverUrl);
-  if (/^https?:\/\//i.test(u)) {
-    return u;
-  }
-  return Host05 + u;
+    const d = dollarActivity.value;
+    if (!d || !d.coverUrl) {
+        return "";
+    }
+    const u = String(d.coverUrl);
+    if (/^https?:\/\//i.test(u)) {
+        return u;
+    }
+    return Host05 + u;
 })
 
 const dollarActivityDate = computed(() => {
-  const d = dollarActivity.value;
-  if (!d) {
-    return "";
-  }
-  const raw =
-    d.revokeDate ||
-    d.activityEndTime ||
-    d.endDate ||
-    d.endTime ||
-    d.activityStartTime ||
-    "";
-  if (!raw) {
-    return "";
-  }
-  return String(raw).split(" ")[0];
+    const d = dollarActivity.value;
+    if (!d) {
+        return "";
+    }
+    const raw =
+        d.revokeDate ||
+        d.activityEndTime ||
+        d.endDate ||
+        d.endTime ||
+        d.activityStartTime ||
+        "";
+    if (!raw) {
+        return "";
+    }
+    return String(raw).split(" ")[0];
 })
 
 const dollarParticipateEnabled = computed(() => {
-  return dollarActivity.value && Number(dollarActivity.value.customApply) === 1})
+    return dollarActivity.value && Number(dollarActivity.value.customApply) === 1
+})
 
 
 const isGuoQin = computed(() => {
@@ -2534,7 +2537,54 @@ const toSingle = (id: string, listID?: string) => {
         })
     }
 }
+const goDollarActivityDetail = () => {
+    uni.navigateTo({
+        url: `/pages/activities/content?id=&type=1&active=dollar`,
+    })
+}
+const goDollarTaskList = () => {
+    uni.navigateTo({
+        url: `/pages/activities/dollar-list`,
+    })
+}
+const openDollarParticipate = async () => {
+    
+    if (!dollarParticipateEnabled.value) {
+        return;
+    }
+    try {
+        await confirm({
+            title: t("DollarActivity.confirmParticipate"),
+            content: t("Msg.SystemPrompt"),
+            confirmText: t("Btn.Confirm"),
+            cancelText: t("Btn.Cancel"),
+        })
+    } catch {
+        return;
+    }
+    if (flag.value) {
+        return;
+    } else {
+        flag.value = true;
+    }
 
+    let res = await activityApi.ActivityDollarAdd({});
+    if (res.code == Code.StatusOK) {
+        uni.showToast({
+            title: res.msg,
+            icon: "success",
+        })
+        getActivityShowsInfo();
+        flag.value = false;
+        tableRef.value?.reload()
+    } else {
+        uni.showToast({
+            title: res.msg,
+            icon: "none",
+        })
+        flag.value = false;
+    }
+}
 const handleValueInfoChange = (value: any) => {
     const selectedAccountObj = loginOptions1.value.find((item) => item.login === value)
     console.log("选中的账户对象:", selectedAccountObj)
@@ -2619,8 +2669,8 @@ onReachBottom(() => {
 <style scoped lang="scss">
 @import "@/uni.scss";
 
-.card{
-  color: var(--cwg-gray-color);
+.card {
+    color: var(--cwg-gray-color);
 }
 
 // 弹窗样式优化
@@ -2670,10 +2720,12 @@ onReachBottom(() => {
 .surplusActivityDialog {
     height: 300px;
 }
+
 .dollar-activity-html {
-  word-break: break-word;
-  :deep(p) {
-    margin: 0 0 6px;
-  }
+    word-break: break-word;
+
+    :deep(p) {
+        margin: 0 0 6px;
+    }
 }
 </style>

+ 0 - 1
pages/ib/components/applyIbDialog.vue

@@ -619,7 +619,6 @@
     .commission-table {
       table-layout: auto !important;
     }
-
   }
 
 

+ 13 - 0
service/activity.ts

@@ -139,4 +139,17 @@ export const activityApi = {
   ActivityShowsInfo: (params = {}) => post('/custom/activity/shows/info', params, 'Host80'),
   /** 获取活动显示信息 */
   getWebsdkLink: (params = {}) => post('/remittance/channel/getWebsdkLink', params, 'Host04'),
+  // 美金活动报名
+  ActivityDollarAdd: (params = {}) => post('/custom/activity/dollar/add', params, 'Host80'),
+  // 美金活动任务列表
+  ActivityDollarSearchList: (params = {}) => post('/custom/activity/dollar/search/list', params, 'Host80'),
+  // 美金活动奖励规则(下拉)
+  ActivityDollarRule: (params = {}) => post('/custom/activity/dollar/rule', params, 'Host80'),
+  // 美金活动申请奖励
+  ActivityDollarApply: (params = {}) => post('/custom/activity/dollar/apply', params, 'Host80'),
+  // 美金活动申请奖励记录
+  ActivityDollarGiveRecord: (params = {}) => post('/custom/activity/dollar/give', params, 'Host80'),
+  // 美金活动取消
+  ActivityDollarCancel: (params = {}) => post('/custom/activity/dollar/cancel', params, 'Host80'),
+
 };