积分 fix

积分 fix
This commit is contained in:
amypeng 2026-05-31 17:31:29 +08:00
parent 60bca13632
commit 5a1ac96d9f
10 changed files with 604 additions and 28 deletions

View File

@ -1,20 +1,32 @@
import React, { useEffect, useState } from 'react';
import { Modal, Form, Input, Button } from 'antd';
import { Modal, Button } from 'antd';
const { TextArea } = Input;
import IconImg from '../img/user/icon1.png';
import { getImageUrl } from 'educoder'
import { applyAward } from '../api';
import '../indexUser.scss';
function UserAward({ visible , onCancel , onSure , type , username , choosed , history , showCompeleteDialog , user }) {
function UserAward({ visible , onCancel , onSure , member , id }) {
const [ loading , setLoading ] = useState(false);
const [ score , setScore ] = useState(0);
const [ scoreLeft , setScoreLeft ] = useState(0);
useEffect(()=>{
},[visible])
if(visible && member && member.zonePointsAccount && member.zonePointsAccount.availablePoints) {
setScore(member.zonePointsAccount.availablePoints);
setScoreLeft(member.zonePointsAccount.availablePoints - 200);
}
},[visible, member])
function onOk() {
setLoading(true);
applyAward(id).then(res => {
if (res && res.data && res.data.code === 200) {
onSure(res.data.msg);
}
}).finally(() => { setLoading(false) })
}
return(
@ -36,14 +48,14 @@ function UserAward({ visible , onCancel , onSure , type , username , choosed , h
footer={
<div>
<Button onClick={onCancel}>取消</Button>
<Button className="btn_ok" style={{marginLeft:"20px"}} onClick={onOk}>确定</Button>
<Button className="btn_ok" style={{marginLeft:"20px"}} onClick={onOk} loading={loading}>确定</Button>
</div>
}
okText="确定"
cancelText="取消"
>
<div className="info">
<p className="award">您将消耗<label> 200 积分 </label>兑换专属电子荣誉证书当前可用积分 3,456 兑换后剩余 3,256 积分扣除后将自动生成证书无法退回请确认操作请确认是否兑换专属电子荣誉证书</p>
<p className="award">您将消耗<label> 200 积分 </label>兑换专属电子荣誉证书当前可用积分 {score.toLocaleString()} 兑换后剩余 {scoreLeft.toLocaleString()} 积分扣除后将自动生成证书无法退回请确认操作请确认是否兑换专属电子荣誉证书</p>
</div>
</Modal>
)

View File

@ -0,0 +1,133 @@
import React, { useEffect, useState } from 'react';
import { Modal, Form, Input, Button, Row, Col } from 'antd';
import { doApplyActivity } from '../api';
const { TextArea } = Input;
import IconImg from '../img/user/icon1.png';
import '../indexUser.scss';
function ApplyActivity({ visible, onCancel, onSure, form, member, zoneName, }) {
const [loading, setLoading] = useState(false);
const { getFieldDecorator, validateFields } = form;
useEffect(() => {
if (visible) {
}
}, [visible]);
function onOk() {
validateFields((err, values) => {
if (!err) {
setLoading(true);
const data = Object.assign({}, values, { zoneId: member.zoneId });
doApplyActivity(data).then(res => {
if (res && res.data && res.data.code === 200) {
onSure(res.data.msg);
}
}).finally(() => { setLoading(false) });
}
});
}
function closeHandler() {
// form.resetFields();
onCancel();
}
return(
<Modal
closeIcon={<i className="iconfont icon-guanbi font-20 closeIconFont" onClick={closeHandler}></i>}
className="qa_modal"
visible={visible}
title={<div className="title_box">
<img alt="头像" src={IconImg} style={{width: '48px', height: '48px'}}></img>
<div className="txt">
<h4>
专家一对一答疑
</h4>
<p>{zoneName}<span> · </span>线下参观/沙龙报名</p>
</div>
</div>}
closable={true}
width={672}
footer={
<div>
<Button onClick={closeHandler}>取消</Button>
<Button className="btn_ok" style={{marginLeft:"20px"}} onClick={onOk} loading={loading}>确定</Button>
</div>
}
okText="确定"
cancelText="取消"
>
<div className="info">
<div className="tipsline">
<i className="iconfont icon-shanchu_tc_icon1"></i>
<div style={{flex: 1}}>
<p>申请将冻结对应积分服务达成后正式扣除若关闭申请积分将退回</p>
</div>
</div>
<Form form={form}>
<Row gutter={40}>
<Col span={12}>
<Form.Item label="真实姓名">
{getFieldDecorator('realName', {
rules: [
{
required: true,
message: '请输入真实姓名'
}
],
})(
<Input placeholder="请输入真实姓名" maxLength={20} />,
)}
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="联系电话">
{getFieldDecorator('phone', {
rules: [
{
required: true,
message: '请输入联系电话'
}
],
})(
<Input placeholder="请输入联系电话" maxLength={20} />,
)}
</Form.Item>
</Col>
</Row>
<Form.Item label="诉求简述">
{getFieldDecorator('description')(
<TextArea maxLength={200} placeholder="请简述您的诉求" autoSize={{ minRows: 3, maxRows: 3 }} showcount="true" />,
)}
</Form.Item>
<Form.Item label="所属单位">
{getFieldDecorator('organization')(
<Input placeholder="请输入所属单位" maxLength={50} />,
)}
</Form.Item>
<Row gutter={40}>
<Col span={12}>
<Form.Item label="微信号">
{getFieldDecorator('wechat')(
<Input placeholder="请输入微信号" maxLength={30} />,
)}
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="邮箱">
{getFieldDecorator('email')(
<Input placeholder="请输入邮箱" maxLength={50} />,
)}
</Form.Item>
</Col>
</Row>
</Form>
</div>
</Modal>
)
}
export default Form.create()(ApplyActivity);

View File

@ -0,0 +1,133 @@
import React, { useEffect, useState } from 'react';
import { Modal, Form, Input, Button, Row, Col } from 'antd';
import { doApplyQA } from '../api';
const { TextArea } = Input;
import IconImg from '../img/user/icon1.png';
import '../indexUser.scss';
function ApplyQA({ visible, onCancel, onSure, form, member, zoneName }) {
const [loading, setLoading] = useState(false);
const { getFieldDecorator, validateFields } = form;
useEffect(() => {
if (visible) {
}
}, [visible]);
function onOk() {
validateFields((err, values) => {
if (!err) {
setLoading(true);
const data = Object.assign({}, values, { zoneId: member.zoneId });
doApplyQA(data).then(res => {
if (res && res.data && res.data.code === 200) {
onSure(res.data.msg);
}
}).finally(() => { setLoading(false) });
}
});
}
function closeHandler() {
// form.resetFields();
onCancel();
}
return(
<Modal
closeIcon={<i className="iconfont icon-guanbi font-20 closeIconFont" onClick={closeHandler}></i>}
className="qa_modal"
visible={visible}
title={<div className="title_box">
<img alt="头像" src={IconImg} style={{width: '48px', height: '48px'}}></img>
<div className="txt">
<h4>
专家一对一答疑
</h4>
<p>{zoneName}<span> · </span>专家一对一答疑</p>
</div>
</div>}
closable={true}
width={672}
footer={
<div>
<Button onClick={closeHandler}>取消</Button>
<Button className="btn_ok" style={{marginLeft:"20px"}} onClick={onOk} loading={loading}>确定</Button>
</div>
}
okText="确定"
cancelText="取消"
>
<div className="info">
<div className="tipsline">
<i className="iconfont icon-shanchu_tc_icon1"></i>
<div style={{flex: 1}}>
<p>申请将冻结对应积分服务达成后正式扣除若关闭申请积分将退回</p>
</div>
</div>
<Form form={form}>
<Row gutter={40}>
<Col span={12}>
<Form.Item label="真实姓名">
{getFieldDecorator('realName', {
rules: [
{
required: true,
message: '请输入真实姓名'
}
],
})(
<Input placeholder="请输入真实姓名" maxLength={20} />,
)}
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="联系电话">
{getFieldDecorator('phone', {
rules: [
{
required: true,
message: '请输入联系电话'
}
],
})(
<Input placeholder="请输入联系电话" maxLength={20} />,
)}
</Form.Item>
</Col>
</Row>
<Form.Item label="诉求简述">
{getFieldDecorator('description')(
<TextArea maxLength={200} placeholder="请简述您的诉求" autoSize={{ minRows: 3, maxRows: 3 }} showcount="true" />,
)}
</Form.Item>
<Form.Item label="所属单位">
{getFieldDecorator('organization')(
<Input placeholder="请输入所属单位" maxLength={50} />,
)}
</Form.Item>
<Row gutter={40}>
<Col span={12}>
<Form.Item label="微信号">
{getFieldDecorator('wechat')(
<Input placeholder="请输入微信号" maxLength={30} />,
)}
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="邮箱">
{getFieldDecorator('email')(
<Input placeholder="请输入邮箱" maxLength={50} />,
)}
</Form.Item>
</Col>
</Row>
</Form>
</div>
</Modal>
)
}
export default Form.create()(ApplyQA);

View File

@ -3,12 +3,11 @@ import { Modal, Form, Input, Button, Spin, Pagination } from 'antd';
import Nodata from '../../Nodata';
import { getNewsMyList, getApplyMyList } from '../api';
import { getNewsMyList, getApplyMyList, doDocTop } from '../api';
const { TextArea } = Input;
import IconImg from '../img/user/icon1.png';
import { getImageUrl } from 'educoder'
@ -22,6 +21,13 @@ function PointsDoc({ visible , onCancel , onSure , type , username , choosed , h
const [ isSpin , setIsSpin ] = useState(true);
const [ list , setList ] = useState(undefined);
const [ currentId , setCurrentId ] = useState(null);
const [ currentRow , setCurrentRow ] = useState(null);
useEffect(()=>{
if(visible && member) {
setPage(1);
}
},[visible, member])
useEffect(()=>{
if(visible && member) {
@ -29,17 +35,26 @@ function PointsDoc({ visible , onCancel , onSure , type , username , choosed , h
}
},[visible, member])
useEffect(()=>{
if(visible && member) {
getMyNews();
}
},[page])
async function init() {
setIsSpin(true);
try{
let result = await getApplyMyList({
zoneId: member.zoneId,
applyType: 'doc',
status:1,
pageSize:limit,
pageNum:page
});
let rows = result.data && result.data.rows;
// let result = await getApplyMyList({
// zoneId: member.zoneId,
// applyType: 'doc',
// status:1,
// pageSize:limit,
// pageNum:page
// });
// let rows = result.data && result.data.rows;
// TODO
let rows = null;
if(Array.isArray(rows) && rows.length > 0) {
setCurrentId(rows[0].applyId)
} else {
@ -57,8 +72,13 @@ function PointsDoc({ visible , onCancel , onSure , type , username , choosed , h
let rows = result.data && result.data.rows;
if(rows && rows.length>0){
setList(rows);
if(currentId){
const row = rows.find(item => item.applyId === currentId || item.id === currentId);
setCurrentRow(row || null);
}
}else{
setList([]);
setCurrentRow(null);
}
setTotal(result.data.total);
}
@ -66,6 +86,17 @@ function PointsDoc({ visible , onCancel , onSure , type , username , choosed , h
function onOk() {
}
async function handlePin(item) {
setIsSpin(true);
try {
let data = Object.assign({}, item, {zoneId: member.zoneId});
await doDocTop(data);
onSure();
} finally {
setIsSpin(false);
}
}
return(
<Modal
closeIcon={<i className="iconfont icon-guanbi font-20 closeIconFont" onClick={onCancel}></i>}
@ -91,11 +122,19 @@ function PointsDoc({ visible , onCancel , onSure , type , username , choosed , h
<span className="content">新闻标题</span>
<span className="action">操作</span>
</div>
{currentRow && (
<div className="line dataline">
<span className="content">{currentRow.name}</span>
<span className="action">
<Button type="primary" shape="round" disabled style={{backgroundColor:'rgba(70, 106, 255, 0.43)', borderColor:'rgba(70, 106, 255, 0.43)', color:'#fff'}}>已置顶</Button>
</span>
</div>
)}
{list && list.map((item) => (
<div className="line dataline" key={item.id}>
<span className="content">{item.name}</span>
<span className="action">
<Button type="primary" shape="round" disabled={!!currentId}>置顶</Button>
<Button type="primary" shape="round" disabled={!!currentRow} onClick={() => handlePin(item)}>置顶</Button>
</span>
</div>
))}
@ -105,7 +144,7 @@ function PointsDoc({ visible , onCancel , onSure , type , username , choosed , h
{
total > limit &&
<div style={{padding:"20px",textAlign:"right"}}>
<Pagination showQuickJumper current={page} total={total} pageSize={limit} onChange={(p)=>{setPage(p);window.scrollTo(0,450)}}/>
<Pagination showQuickJumper current={page} total={total} pageSize={limit} onChange={(p)=>{setPage(p);}}/>
</div>
}
</div>

View File

@ -13,8 +13,8 @@ export const memberStatusEnum = {
const transactionTypeMap = {
add: { className: 'green', prefix: '+', valueKey: 'points', status: '已到账', statusClass: 'green' },
// TODO: transactionType
// deduct: { className: 'red', prefix: '-', valueKey: 'points', status: '' },
// frozen: { className: 'gray', prefix: '', valueKey: 'points', status: '' },
deduct: { className: 'red', prefix: '-', valueKey: 'points', status: '已支付', statusClass: 'blue' },
freezed: { className: 'orange', prefix: '-', valueKey: 'points', status: '冻结中', statusClass: 'orange' },
// unfrozen: { className: 'blue', prefix: '', valueKey: 'points', status: '' },
};

View File

@ -1,5 +1,5 @@
import React , { useState , useEffect } from 'react';
import { Spin } from 'antd';
import { Spin, Modal, Button } from 'antd';
import { getMainInfos, getAuditStatus, getMemberInfo, applyJoin, updateSelfInfo, setZoneVisits } from '../api';
import { Link } from 'react-router-dom';
import {getUniqueIdentifier,getUserName,getBrowserPlatform,getBrowserBrand} from '../utils';
@ -18,11 +18,16 @@ import ZjdyImg from '../img/user/zjdy.png';
import StarImg from '../img/user/star.png';
import SuccessImg from '../img/user/success.png';
import ScoreRlue from './scoreRule';
import UserEdit from '../Component/UserEdit';
import UserAward from '../Component/UserAward';
import MemberApply from '../Component/memberApply';
import PointsDoc from '../Component/pointsDoc';
import ApplyAcitvity from '../Component/applyAcitvity';
import ApplyQA from '../Component/applyQA';
import '../indexUser.scss';
@ -41,7 +46,11 @@ function ZoneUser(props){
const [ applyVisible , setApplyVisible ] = useState(false);
const [ awardVisible , setAwardVisible ] = useState(false);
const [ docVisible , setDocVisible ] = useState(false);
const [ acitvityVisible , setAcitvityVisible ] = useState(false);
const [ qaVisible , setQaVisible ] = useState(false);
const [ successVisible , setSuccessVisible ] = useState(false);
const [ timeNum, setTimeNum] = useState(3);
const { id, showNotification, checkIfLogin, showLoginDialog, temp, sectionMemberTitle } = props;
useEffect(()=>{
@ -62,6 +71,23 @@ function ZoneUser(props){
}
},[id])
useEffect(() => {
if (successVisible) {
const pid = setInterval(() => {
setTimeNum(prev => {
const newVal = prev - 1;
console.log('ttt', newVal);
if (newVal <= 0) {
clearInterval(pid);
setSuccessVisible(false);
}
return newVal;
});
}, 1000);
return () => clearInterval(pid);
}
}, [successVisible]);
const infoItemsData = [{
img: JszdImg,
title: '专家技术指导',
@ -192,11 +218,21 @@ function ZoneUser(props){
setApplyVisible(!applyVisible)
}
function handleAwardSure(msg) {
showNotification(msg);
setAwardVisible(false);
getInfo();
}
function pointsCustom(item) {
if(item.key == 'certificate') {
setAwardVisible(true);
} else if(item.key == 'doc') {
setDocVisible(true);
} else if(item.key == 'acitvity') {
setAcitvityVisible(true);
} else if(item.key == 'qa') {
setQaVisible(true);
}
}
@ -299,12 +335,34 @@ function ZoneUser(props){
<UserEdit visible={visible} member={memberInfo} zoneName={zoneInfo?.name} onSure={ onSure }
onCancel={()=>setVisible(false)}
/>
<UserAward visible={awardVisible} user={props.current_user}
<UserAward visible={awardVisible} member={memberInfo} id={id} onSure={(msg) => handleAwardSure(msg)}
onCancel={()=>setAwardVisible(false)}
/>
<PointsDoc visible={docVisible} member={memberInfo}
onCancel={()=>setDocVisible(false)}
<PointsDoc visible={docVisible} member={memberInfo}
onCancel={()=>setDocVisible(false)} onSure={() => { setDocVisible(false); setSuccessVisible(true);getInfo();}}
/>
<ApplyAcitvity visible={acitvityVisible} member={memberInfo} zoneName={zoneInfo?.name}
onCancel={()=>setAcitvityVisible(false)} onSure={() => { setQaVisible(false); getInfo();}}
/>
<ApplyQA visible={qaVisible} member={memberInfo} zoneName={zoneInfo?.name}
onCancel={()=>setQaVisible(false)} onSure={() => { setQaVisible(false); getInfo();}}
/>
<Modal
title=""
className="success_modal"
closeIcon={<i className="iconfont icon-guanbi font-20 closeIconFont" onClick={() => {setSuccessVisible(false)}}></i>}
visible={successVisible}
closable={true}
footer={null}
width={466}
>
<div className="info">
<img src={SuccessImg} alt=""/>
<p>恭喜获得专区<label>首页新闻推荐</label></p>
<Button className="btn_ok" onClick={() => {setSuccessVisible(false)}}>确定({timeNum}s)</Button>
</div>
</Modal>
</div>
)
}

View File

@ -640,4 +640,35 @@ export function deleteMemberProject(ids){
url: `/zone/zoneFront/removeProject/${ids}`,
method: 'delete',
})
}
}
export function applyAward(id) {
return fetch({
url: `/zone/points/account/certificate/redeem/${id}`,
method: 'post'
});
}
export function doApplyQA(data) {
return fetch({
url: `/zone/points/account/expert/qa/freeze`,
method: 'post',
data
});
}
export function doApplyActivity(data) {
return fetch({
url: `/zone/points/account/offlineActivity/freeze`,
method: 'post',
data
});
}
export function doDocTop(data) {
return fetch({
url: `/zone/points/account/article/top`,
method: 'post',
data
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

View File

@ -531,6 +531,12 @@
&.green{
color:#1ca73c;
}
&.red{
color:#f5383b;
}
&.orange{
color:#e05a00;
}
}
&.remark{
color:#4a5377;
@ -768,6 +774,119 @@
}
.qa_modal{
.ant-modal-content{
padding-top: 20px;
border-radius: 16px;
background-image: url(./img/user/userMBg.png);
background-position: top center;
background-size: 100% auto;
background-repeat: no-repeat;
background-color: #FFF;
font-family: alibabaReg;
color: #191919;
.ant-modal-close{
top: 78px !important;
right: 50px;
span{
width: 20px;
height: 20px;
line-height: 20px;
color: #4a5377;
}
}
}
.ant-modal-header{
padding: 36px 0 24px 0;
border-radius: 16px 16px 0px 0;
background-image: url(./img/user/userMBg2.png);
background-position: top center;
background-size: 100% auto;
background-repeat: no-repeat;
border-bottom: 2px dotted rgba(70, 106, 255, 0.25);
.ant-modal-title{
height: 60px;
line-height: 60px !important;
}
.title_box{
display: flex;
margin-left: 40px;
align-items: center;
.txt{
display: flex;
flex-direction: column;
align-items: start;
margin-left: 24px;
background: transparent;
}
h4{
text-align: left;
color: #191919;
height: 24px;
line-height: 24px;
margin-bottom: 16px !important;
font-family: alibaba;
font-size: 17px;
}
p{
color:#4a5377;
font-size:15px;
height: 21px;
line-height: 21px;
font-weight: 400;
}
}
}
.ant-modal-body,.ant-modal-footer{
background-color: #FFF;
}
.ant-modal-body{
background-color: #FFF;
background-image: url(./img/user/userMBg2.png);
background-position: top -124px left 0px;
background-size: 100% auto;
background-repeat: no-repeat;
padding: 20px 40px 10px 50px;
.info{
display: flex;
flex-direction: column;
.tipsline{
display: flex;
align-items: center;
color: #d31215;
margin-bottom: 30px;
p{
margin-left: 10px;
font-size: 15px;
font-family: alibabaReg;
}
}
}
.ant-form-item label{
color:#191919;
font-size:15px;
}
}
.ant-modal-footer{
border-top: none;
padding-top: 0;
padding-bottom: 32px;
text-align: center;
border-radius: 16px;
button{
width: 120px;
height: 36px;
line-height: 36px;
}
.btn_ok{
border: 1px solid #6e90ff;
color: white;
background:linear-gradient(91.72deg,#694dff -2.85%,#1d5bff 99.65%);
}
}
}
.doc_modal{
.ant-modal-content{
border-radius: 16px;
@ -872,6 +991,57 @@
}
.success_modal{
.ant-modal-content{
border-radius: 16px;
background-image: url(./img/user/successBg.png);
background-position: top center;
background-size: 100% auto;
background-repeat: no-repeat;
}
.ant-modal-close{
top: 20px !important ;
right: 24px;
span{
width: 20px;
height: 20px;
line-height: 20px;
color: #191919;
}
}
.ant-modal-body{
padding: 50px 24px 50px 24px;
.info{
display: flex;
flex-direction: column;
align-items: center;
img{
width: 60px;
height: 60px;
}
p{
margin-top: 30px;
margin-bottom: 55px !important;
font-size: 20px;
font-family: alibaba;
color: #191919;
label{
color: #ff7634;
}
}
.btn_ok{
border: 1px solid #6e90ff;
color: white;
background:linear-gradient(91.72deg,#694dff -2.85%,#1d5bff 99.65%);
width: 170px;
height: 36px;
line-height: 36px;
}
}
}
}
body.ant-scrolling-effect {
width: auto !important;
}