diff --git a/public/css/gitlink.min.css b/public/css/gitlink.min.css index 0f9924a83..2fbfc352f 100644 --- a/public/css/gitlink.min.css +++ b/public/css/gitlink.min.css @@ -8,6 +8,10 @@ font-family: "pangmen"; src: url("../fonts/PangMenZhengDaoBiaoTiTiMianFeiBan-2.ttf"); } +@font-face { + font-family: "sanjikai"; + src: url("../fonts/SanJiXingKaiJianTi-Cu-2.ttf"); +} @font-face { font-family: "alibaba"; src: url("../fonts/ALIBABA-PUHUITI-MEDIUM.TTF"); diff --git a/public/fonts/SanJiXingKaiJianTi-Cu-2.ttf b/public/fonts/SanJiXingKaiJianTi-Cu-2.ttf new file mode 100644 index 000000000..a7c6b6882 Binary files /dev/null and b/public/fonts/SanJiXingKaiJianTi-Cu-2.ttf differ diff --git a/src/forge/Information/Component/UserAward.jsx b/src/forge/Information/Component/UserAward.jsx index daa1b1792..3cda1bd3f 100644 --- a/src/forge/Information/Component/UserAward.jsx +++ b/src/forge/Information/Component/UserAward.jsx @@ -1,17 +1,20 @@ import React, { useEffect, useState } from 'react'; -import { Modal, Button } from 'antd'; - +import { Modal, Button, Form, Input } from 'antd'; +import cookie from 'react-cookies'; import IconImg from '../img/user/icon1.png'; +import TemplateImg from '../img/user/template.png'; import { applyAward } from '../api'; +import { httpUrl } from '../fetch'; import '../indexUser.scss'; -function UserAward({ visible , onCancel , onSure , member , id }) { +function UserAward({ visible , onCancel , onSure , member , id, form }) { const [ loading , setLoading ] = useState(false); const [ score , setScore ] = useState(0); const [ scoreLeft , setScoreLeft ] = useState(0); + const { getFieldDecorator, validateFields, getFieldsValue } = form; useEffect(()=>{ if(visible && member && member.zonePointsAccount && member.zonePointsAccount.availablePoints) { @@ -21,12 +24,116 @@ function UserAward({ visible , onCancel , onSure , member , id }) { },[visible, member]) function onOk() { - setLoading(true); - applyAward(id).then(res => { - if (res && res.data && res.data.code === 200) { - onSure(res.data.msg); + validateFields(async (err, values) => { + if (!err) { + try{ + setLoading(true); + let imgInfo = await createImg(values.realName); + + let certificateUrl = ''; + if (imgInfo && imgInfo.code == 200 && imgInfo.url) { + certificateUrl = imgInfo.url || ''; + } + + const res = await applyAward({zoneId: id, sourceData: certificateUrl}); + setLoading(false); + + if (res && res.data && res.data.code === 200) { + onSure(res.data.msg); + } + }finally{ + setLoading(false); + } } - }).finally(() => { setLoading(false) }) + }); + } + + async function waitFontLoaded() { + // 等待自定义字体加载完成 + if (document.fonts) { + await document.fonts.ready; + if(!document.fonts.check('64px sanjikai')) { + try { + const font = new FontFace('sanjikai', 'url(/fonts/SanJiXingKaiJianTi-Cu-2.ttf)'); + await font.load(); + document.fonts.add(font); + } catch (e) { + console.warn('sanjikai 字体加载失败:', e); + } + } + + if(!document.fonts.check('18px alibabaReg')) { + try { + const font = new FontFace('alibabaReg', 'url(/fonts/ALIBABA-PUHUITI-REGULAR.TTF)'); + await font.load(); + document.fonts.add(font); + } catch (e) { + console.warn('alibabaReg 字体加载失败:', e); + } + } + } + } + + + async function createImg(realName) { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + + const img = new Image(); + img.crossOrigin = 'anonymous'; + img.src = TemplateImg; + + await new Promise((resolve, reject) => { + img.onload = resolve; + img.onerror = reject; + }); + + // 等待字体加载完成后再绘制 + await waitFontLoaded(); + + canvas.width = img.width; + canvas.height = img.height; + ctx.drawImage(img, 0, 0); + + const memberName = realName || member?.name || member?.nickname || '学员'; + const awardDate = new Date().toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric' }); + + // 设置文字样式 + ctx.font = '64px sanjikai'; + ctx.fillStyle = '#04060c'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'bottom'; + ctx.fillText(memberName, canvas.width / 2, 705); + + ctx.font = '18px alibabaReg'; + ctx.fillStyle = '#04060c'; + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; + ctx.fillText(awardDate, 240, 1008); + + // TODO + const dataUrl = canvas.toDataURL('image/png'); + const link = document.createElement('a'); + link.download = `荣誉证书_${memberName}_${new Date().getTime()}.png`; + link.href = dataUrl; + link.click(); + + const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png')); + const formData = new FormData(); + formData.append('file', blob, `member_${member.id}.png`); + formData.append('type', 'resource'); + + const uploadRes = await fetch(`${httpUrl}/file/common/upload`, { + method: 'POST', + body: formData, + headers: { + // Authorization: '6d72497d7f197eb9dc8a15db038881cd31afea7a', + Authorization: cookie.load('autologin_trustie'), + } + }); + + const uploadData = await uploadRes.json(); + return uploadData; } return( @@ -56,8 +163,22 @@ function UserAward({ visible , onCancel , onSure , member , id }) { >

您将消耗兑换「专属电子荣誉证书」,当前可用积分 {score.toLocaleString()} 分,兑换后剩余 {scoreLeft.toLocaleString()} 分。积分扣除后将自动生成证书,无法退回,请确认操作。请确认是否兑换专属电子荣誉证书?

+
+ + {getFieldDecorator('realName', { + rules: [ + { + required: true, + message: '请输入真实姓名' + } + ], + })( + , + )} + +
) } -export default UserAward; \ No newline at end of file +export default Form.create()(UserAward); \ No newline at end of file diff --git a/src/forge/Information/Component/applyAcitvity.jsx b/src/forge/Information/Component/applyAcitvity.jsx index 61b52df15..344daaeac 100644 --- a/src/forge/Information/Component/applyAcitvity.jsx +++ b/src/forge/Information/Component/applyAcitvity.jsx @@ -45,7 +45,7 @@ function ApplyActivity({ visible, onCancel, onSure, form, member, zoneName, }) { 头像

- 专家一对一答疑 + 线下参观/沙龙报名

{zoneName} · 线下参观/沙龙报名

diff --git a/src/forge/Information/Pages/zoneUser.jsx b/src/forge/Information/Pages/zoneUser.jsx index 6b51cb4a0..ebfdfa23d 100644 --- a/src/forge/Information/Pages/zoneUser.jsx +++ b/src/forge/Information/Pages/zoneUser.jsx @@ -50,6 +50,7 @@ function ZoneUser(props){ const [ qaVisible , setQaVisible ] = useState(false); const [ successVisible , setSuccessVisible ] = useState(false); const [ timeNum, setTimeNum] = useState(3); + const [ memberAccountInfo, setMemberAccountInfo ] = useState([]); const { id, showNotification, checkIfLogin, showLoginDialog, temp, sectionMemberTitle } = props; @@ -71,6 +72,36 @@ function ZoneUser(props){ } },[id]) + useEffect(() => { + let temp = awardsInfoData.map(item => { + let tempData = Object.assign({}, item); + if(!memberInfo) return tempData; + + if(item.key === 'certificate' && memberInfo.pointsEvent?.id) { + tempData.exist = true; + tempData.txt = '下载证书'; + } + if(item.key === 'acitvity' && Array.isArray(memberInfo.applyList)) { + let index = memberInfo.applyList.findIndex(item => item.applyType === 'offlineActivityFreeze'); + if(index !== -1) { + tempData.disabled = true; + tempData.txt = '等待审核'; + } + } + if(item.key === 'qa' && Array.isArray(memberInfo.applyList)) { + let index = memberInfo.applyList.findIndex(item => item.applyType === 'expertQaFreeze'); + if(index !== -1) { + tempData.disabled = true; + tempData.txt = '等待审核'; + } + } + + return tempData; + }) + + setMemberAccountInfo(temp); + }, [memberInfo]) + useEffect(() => { if (successVisible) { const pid = setInterval(() => { @@ -225,8 +256,16 @@ function ZoneUser(props){ } function pointsCustom(item) { + if(item.disabled) return; + console.log('iii', item) if(item.key == 'certificate') { - setAwardVisible(true); + if(!item.exist) { + setAwardVisible(true); + } else { + let url = memberInfo.pointsEvent?.sourceData; + console.log('uuu', url) + window.open(url, '_blank'); + } } else if(item.key == 'doc') { setDocVisible(true); } else if(item.key == 'acitvity') { @@ -305,16 +344,16 @@ function ZoneUser(props){
{ - awardsInfoData.map((item, index) => ( + memberAccountInfo.map((item, index) => (

{item.title}

{item.desc}

/{item.unit} - {memberInfo?.zonePointsAccount?.availablePoints >= item.score ? ( -
pointsCustom(item)}> - {item.txt} -
+ {memberInfo?.zonePointsAccount?.availablePoints >= item.score ? ( +
pointsCustom(item)}> + {item.txt} +
) : (
积分不足 @@ -342,10 +381,10 @@ function ZoneUser(props){ onCancel={()=>setDocVisible(false)} onSure={() => { setDocVisible(false); setSuccessVisible(true);getInfo();}} /> setAcitvityVisible(false)} onSure={() => { setQaVisible(false); getInfo();}} + onCancel={()=>setAcitvityVisible(false)} onSure={() => { showNotification(msg); setAcitvityVisible(false); getInfo();}} /> setQaVisible(false)} onSure={() => { setQaVisible(false); getInfo();}} + onCancel={()=>setQaVisible(false)} onSure={() => { showNotification(msg); setQaVisible(false); getInfo();}} />