feat(admin): 从文章详情页面改为文章管理页面

- 修改页面配置,设置新的导航栏标题和样式
- 重新设计页面布局,增加搜索栏、文章列表和操作按钮
- 添加文章搜索、分页加载和删除功能
- 优化文章列表项的样式和交互
- 新增礼品卡相关API和组件
- 更新优惠券组件,增加到期提醒和筛选功能
This commit is contained in:
2025-08-13 10:11:57 +08:00
parent 0e457f66d8
commit a1cacc04e8
67 changed files with 6278 additions and 2816 deletions

View File

@@ -1,221 +1,31 @@
import { useState, useEffect } from 'react'
import { View, Canvas, Image } from '@tarojs/components'
import Taro from '@tarojs/taro'
import { Button } from '@nutui/nutui-react-taro'
import './index.scss'
interface UserInfo {
id: string
nickname: string
avatar: string
inviteCode: string
}
function PromotionQRCode() {
const [userInfo, setUserInfo] = useState<UserInfo>({
id: '12345',
nickname: '分销达人',
avatar: 'https://img12.360buyimg.com/imagetools/jfs/t1/143702/31/16654/116794/5fc6f541Edebf8a57/4138097748889987.png',
inviteCode: 'INV12345'
})
const [qrCodeUrl, setQrCodeUrl] = useState('')
const [loading, setLoading] = useState(false)
useEffect(() => {
Taro.setNavigationBarTitle({
title: '推广二维码'
})
generateQRCode()
}, [])
const generateQRCode = async () => {
try {
setLoading(true)
// 模拟生成二维码
// 实际项目中应该调用后端API生成包含邀请码的二维码
const inviteUrl = `https://your-domain.com/invite?code=${userInfo.inviteCode}`
// 这里使用一个模拟的二维码图片
// 实际项目中可以使用二维码生成库或调用API
const mockQRCode = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='
setTimeout(() => {
setQrCodeUrl(mockQRCode)
setLoading(false)
}, 1000)
} catch (error) {
console.error('生成二维码失败:', error)
setLoading(false)
Taro.showToast({
title: '生成失败',
icon: 'error'
})
}
}
const handleSaveImage = async () => {
try {
if (!qrCodeUrl) {
Taro.showToast({
title: '二维码未生成',
icon: 'none'
})
return
}
// 在实际项目中,这里应该将二维码保存到相册
Taro.showModal({
title: '保存二维码',
content: '是否保存二维码到相册?',
success: (res) => {
if (res.confirm) {
// 实际保存逻辑
Taro.showToast({
title: '保存成功',
icon: 'success'
})
}
}
})
} catch (error) {
console.error('保存图片失败:', error)
Taro.showToast({
title: '保存失败',
icon: 'error'
})
}
}
const handleShareQRCode = () => {
Taro.showActionSheet({
itemList: ['分享给朋友', '分享到朋友圈', '复制邀请链接'],
success: (res) => {
const actions = ['分享给朋友', '分享到朋友圈', '复制邀请链接']
const action = actions[res.tapIndex]
if (action === '复制邀请链接') {
const inviteUrl = `https://your-domain.com/invite?code=${userInfo.inviteCode}`
Taro.setClipboardData({
data: inviteUrl,
success: () => {
Taro.showToast({
title: '链接已复制',
icon: 'success'
})
}
})
} else {
Taro.showToast({
title: action,
icon: 'none'
})
}
}
})
}
const handleRefreshQRCode = () => {
Taro.showModal({
title: '刷新二维码',
content: '确定要重新生成二维码吗?',
success: (res) => {
if (res.confirm) {
generateQRCode()
}
}
})
}
import React from 'react'
import { View, Text, Image } from '@tarojs/components'
import { Cell, Button } from '@nutui/nutui-react-taro'
const DealerQrcode: React.FC = () => {
return (
<View className="promotion-qrcode-page">
{/* 用户信息卡片 */}
<View className="user-card">
<Image className="user-avatar" src={userInfo.avatar} />
<View className="user-info">
<View className="user-name">{userInfo.nickname}</View>
<View className="invite-code">{userInfo.inviteCode}</View>
<View className="p-4">
<Text className="text-lg font-bold mb-4">广</Text>
<View className="text-center">
<View className="bg-gray-100 w-48 h-48 mx-auto mb-4 flex items-center justify-center">
<Text className="text-gray-500"></Text>
</View>
</View>
{/* 二维码展示区域 */}
<View className="qrcode-container">
<View className="qrcode-card">
<View className="qrcode-header">
<View className="title">广</View>
<View className="subtitle"></View>
</View>
<View className="qrcode-wrapper">
{loading ? (
<View className="qrcode-loading">
<View className="loading-text">...</View>
</View>
) : (
<View className="qrcode-image-container">
{/* 实际项目中这里应该显示真实的二维码 */}
<View className="qrcode-placeholder">
<View className="qr-pattern">
<View className="qr-corner top-left"></View>
<View className="qr-corner top-right"></View>
<View className="qr-corner bottom-left"></View>
<View className="qr-dots">
{Array.from({ length: 25 }).map((_, index) => (
<View key={index} className="qr-dot"></View>
))}
</View>
</View>
</View>
<View className="qrcode-tip"></View>
</View>
)}
</View>
<View className="qrcode-info">
<View className="info-item">
<View className="info-label"></View>
<View className="info-value">https://your-domain.com/invite?code={userInfo.inviteCode}</View>
</View>
</View>
</View>
</View>
{/* 操作按钮 */}
<View className="action-buttons">
<Button
className="action-btn primary"
onClick={handleSaveImage}
disabled={loading}
>
<Text className="text-sm text-gray-600 mb-4">
</Text>
<Button type="primary" className="mb-2">
</Button>
<Button
className="action-btn secondary"
onClick={handleShareQRCode}
disabled={loading}
>
<Button>
</Button>
<Button
className="action-btn tertiary"
onClick={handleRefreshQRCode}
disabled={loading}
>
</Button>
</View>
{/* 使用说明 */}
<View className="usage-tips">
<View className="tips-title">使</View>
<View className="tips-list">
<View className="tip-item">1. </View>
<View className="tip-item">2. </View>
<View className="tip-item">3. 广</View>
<View className="tip-item">4. 使</View>
</View>
</View>
</View>
)
}
export default PromotionQRCode
export default DealerQrcode