提交 b798db35 作者: ZhangLingKun

Merge remote-tracking branch 'origin/develop'

......@@ -31,6 +31,14 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
- name: WeChat Work notification by text
uses: chf007/action-wechat-work@master
env:
WECHAT_WORK_BOT_WEBHOOK: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=9be1b073-1760-442d-8e3d-faa0fd32ea16
with:
msgtype: text
content: "GitHub提交信息\n - 提交人: ${{github.actor}}\n - 提交信息: ${{ github.event.head_commit.message }}\n - 提交到仓库: ${{github.repository}}\n - 提交到分支: ${{github.ref}}\n 即将开始更新,请关注Argocd同步状态..."
- name: Login to ACR EE with the AccessKey pair
uses: aliyun/acr-login@v1
with:
......
const dev = {
baseUrl: "/local",
baseUrl: '/local',
};
const prod = {
baseUrl: "",
baseUrl: '',
};
export default process.env.NODE_ENV === "development" ? dev : prod;
export default process.env.NODE_ENV === 'development' ? dev : prod;
......@@ -79,6 +79,10 @@ export default {
imgOss: () => {
return config.baseUrl + '/pms/upload/imgOss';
},
//文件上传地址
fileUpload: () => {
return config.baseUrl + '/pms/upload/breakpoint';
},
//宣传中心
listBannerImg: (
moduleCode: string,
......
import config from './config';
let loginTimeout: NodeJS.Timeout | undefined;
......@@ -10,7 +9,12 @@ let loginTimeout: NodeJS.Timeout | undefined;
* @param options 额外参数
* @returns Promise<Response>
*/
export default function request(url: string, method: String = 'get', data?: any, options: any & { hideError?: boolean, headers?: { token?: string } } = {}): Promise<Response<any>> {
export default function request(
url: string,
method: String = 'get',
data?: any,
options: any & { hideError?: boolean; headers?: { token?: string } } = {},
): Promise<Response<any>> {
let token = localStorage.getItem('token') || '';
switch (method.toLowerCase()) {
......@@ -19,7 +23,7 @@ export default function request(url: string, method: String = 'get', data?: any,
if (data) {
Object.keys(data).forEach((key) => {
params.append(key, data[key]);
})
});
url += '?' + params;
}
......@@ -33,16 +37,16 @@ export default function request(url: string, method: String = 'get', data?: any,
},
body: JSON.stringify(data),
...options,
}
};
break;
}
if(options.headers){
if (options.headers) {
options.headers.token = token;
}else{
} else {
options.headers = {
token
}
token,
};
}
/**
......@@ -59,63 +63,63 @@ export default function request(url: string, method: String = 'get', data?: any,
* 未登录消息展示,1.5秒内限制只展示一次
* @returns
*/
function loginErrorMsg(){
console.log('loginTimeout', loginTimeout)
if(loginTimeout){
function loginErrorMsg() {
console.log('loginTimeout', loginTimeout);
if (loginTimeout) {
return;
}
loginTimeout = setTimeout(() => {
errMsg('请先登录');
loginTimeout = undefined;
}, 1500)
}, 1500);
}
return fetch(config.baseUrl + url, options)
.then((r) => {
try {
return r.json()
return r.json();
} catch (e) {
console.error(e);
}
return {
code: '-1',
message: '请求失败',
result: null
}
result: null,
};
})
.then((data) => {
if (data.errors) {
//全局消息提示
errMsg('请求出错')
errMsg('请求出错');
if (Array.isArray(data.errors)) {
data.errors.forEach((item: any) => {
if (item.defaultMessage) {
errMsg(item.defaultMessage)
errMsg(item.defaultMessage);
}
})
});
}
return {
code: '-1',
message: '请求失败',
result: null
}
result: null,
};
}
if (data.code !== '200') {
//未登录判断
if(data.code === '5008' || data.code === '2014'){
if (data.code === '5008' || data.code === '2014') {
loginErrorMsg();
window.logout();
}else{
} else {
errMsg(data.message || '请求出错');
}
}
return data;
})
.catch(error => {
.catch((error) => {
if (error.name === 'AbortError') {
console.log('请求已中断');
console.log(error);
......@@ -125,14 +129,14 @@ export default function request(url: string, method: String = 'get', data?: any,
return {
code: '-1',
message: '请求失败',
result: null
}
result: null,
};
});
}
//准备响应结构
export interface Response<T> {
code: string,
message: string,
result?: T | null
code: string;
message: string;
result?: T | null;
}
......@@ -14,8 +14,8 @@ const items: TabsProps['items'] = [
label: ` 首页 `,
},
{
key: '/jobServices',
label: `作业服务`,
key: '/mall',
label: `产品商城`,
},
{
key: '/equipmentLeasing',
......@@ -26,8 +26,8 @@ const items: TabsProps['items'] = [
label: `飞手培训`,
},
{
key: '/mall',
label: `产品商城`,
key: '/jobServices',
label: `作业服务`,
},
{
key: '/projectInfo',
......
import { Col, Modal, Row } from 'antd';
import Image from 'next/image';
import styles from './index.module.scss';
import img from './assets/img.png';
import { useContext, useEffect, useState } from 'react';
import api, { ListTagResp } from './api';
import { useRouter } from 'next/router';
import { UserContext } from '~/lib/userProvider';
import commonApi from '~/api';
const imgs = [
require('./assets/生产制造商.png'),
......@@ -27,7 +27,7 @@ type Props = {
export default function JoinModal(props: Props) {
const router = useRouter();
const [tagList, setTagList] = useState<ListTagResp[]>([]);
const { userInfo } = useContext(UserContext);
const { userInfo, setUserInfo } = useContext(UserContext);
useEffect(() => {
api.listTag().then((res) => {
......@@ -36,12 +36,15 @@ export default function JoinModal(props: Props) {
}, []);
const onClickTag = (item: ListTagResp) => {
if (userInfo!.companyAuthStatus) {
router.replace('/JoinPolicy?tagId=' + item.id);
commonApi.userInfo().then((res) => {
setUserInfo(res.result);
if (res.result!.companyAuthStatus) {
router.replace({ pathname: '/JoinPolicy', query: { tagId: item.id } });
props.onCancel && props.onCancel();
} else {
router.push('/certification');
}
});
};
return (
<Modal
......
......@@ -106,7 +106,12 @@ export default function PublishModal(props: Props) {
name='requireDescription'
rules={[{ required: true, message: '请输入需求描述!' }]}
>
<Input.TextArea placeholder='项目需求描述' style={{ height: 162 }}></Input.TextArea>
<Input.TextArea
placeholder='项目需求描述'
style={{ height: 162 }}
maxLength={256}
showCount
></Input.TextArea>
</Form.Item>
<Form.Item>
<Button
......
import React, { Suspense } from 'react';
import React from 'react';
import { Layout, Space } from 'antd';
import NavHeader from '~/components/NavHeader';
import FooterView from '~/components/footer';
......
import { headers } from 'next/dist/client/components/headers';
import request, { Response } from '~/api/request';
export default {
uploadFile: (data: FormData): Promise<Response<string>> =>
request('/pms/upload/breakpoint', 'post', data, { headers: {}, body: data }),
};
.uploader-view{
.ant-upload-wrapper .ant-upload-list .ant-upload-list-item-container{
//width: 200px !important;
}
}
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import { message, Upload, UploadProps } from 'antd';
// import { UploadFile } from "antd/es/upload/interface";
import './index.scss';
import uploadApi from './api';
interface PropsType {
listType?: 'text' | 'picture' | 'picture-card'; // 上传列表的内建样式
fileSize?: number; // 文件大小
fileType?: string[]; // 上传文件类型
fileUpload: boolean; // 是否上传到服务器(返回文件流还是返回上传后的地址)
fileLength?: number; // 最大上传文件数量
children: React.ReactNode; // 上传按钮
onChange?: (fileList: any[]) => void; // 上传文件改变时的状态
onRemove?: (fileList: any[]) => void;
onChange?: (
fileList: {
id: number;
name: string;
uid: number;
url: string;
}[],
) => void; // 上传文件改变时的状态
defaultFileList?: any[]; // 默认文件列表
}
export const Uploader: React.FC<PropsType> = (props) => {
Uploader.defaultProps = {
listType: 'text',
listType: 'picture-card',
fileSize: 2,
fileLength: 1,
fileType: ['image/png', 'image/jpeg', 'image/jpg', 'image/gif', 'image/bmp'],
fileType: ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'],
onChange: () => {},
onRemove: () => {},
defaultFileList: [],
};
const { fileType, children, listType, fileSize, fileLength, onChange, onRemove } = props;
const {
fileType = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif', 'image/bmp'],
children,
listType,
fileSize,
fileUpload,
fileLength,
onChange,
defaultFileList,
} = props;
const [fileList, setFileList] = useState<any[]>([]);
// 上传文件配置
const uploadProps: UploadProps = {
......@@ -30,34 +46,84 @@ export const Uploader: React.FC<PropsType> = (props) => {
beforeUpload: (res) => {
const isType = fileType?.includes(res.type);
const isSize = res.size / 1024 / 1024 < (fileSize || 2);
const isLength = fileList.length < (fileLength || 1);
if (!isType) {
message.error('请上传正确的格式!').then();
return isType;
message.error('上传文件格式错误!').then();
}
if (!isSize) {
message.error('文件最大2M,请压缩后上传!').then();
return isSize;
message.error(`文件最大${props.fileSize}M,请压缩后上传!`).then();
}
if (!isLength) {
message.error(`最多上传${fileLength || 1}个文件`).then();
}
return isType && isSize && isLength;
},
customRequest: (res) => {
if (fileList.length >= (fileLength || 1)) {
message.error(`最多上传${fileLength || 1}个文件`).then();
return;
if (fileUpload) {
setFileList([
...fileList,
{
id: new Date().getTime(),
uid: new Date().getTime(),
name: (res.file as any).name,
type: (res.file as any).type,
url: (res.file as any).url,
status: 'uploading',
},
]);
// 上传到服务器
const formData = new FormData();
formData.append('uploadFile', res.file);
uploadApi.uploadFile(formData).then(({ result, code }) => {
if (code === '200') {
setFileList([
...fileList,
{
id: new Date().getTime(),
uid: new Date().getTime(),
name: (res.file as any).name || '',
url: result,
type: (res.file as any).type,
status: 'done',
},
]);
onChange?.([
...fileList,
{
id: new Date().getTime(),
uid: new Date().getTime(),
name: (res.file as any).name || '',
url: result,
type: (res.file as any).type,
status: 'done',
},
]);
}
});
} else {
setFileList([...fileList, res.file]);
onChange?.([...fileList, res.file]);
}
},
onRemove: (res) => {
const newFileList = fileList.filter((item) => item.uid !== res.uid);
setFileList(newFileList);
onRemove?.(newFileList);
onChange?.(newFileList);
},
// onPreview: { onPreview },
};
useEffect(() => {
// 如果有默认文件列表
if (defaultFileList?.length) {
setFileList(defaultFileList);
} else {
setFileList([]);
}
}, [defaultFileList]);
return (
<div className='uploader-view'>
<Upload {...uploadProps} style={{ width: '100%' }}>
<>{fileList.length < (fileLength || 1) && children}</>
{children}
</Upload>
</div>
);
......
......@@ -4,7 +4,7 @@ metadata:
name: web-deployment
namespace: default
spec:
# minReadySeconds: 250
minReadySeconds: 10
revisionHistoryLimit: 2
replicas: 1
selector:
......@@ -24,6 +24,7 @@ spec:
cpu: 100m
ports:
- containerPort: 3000
name: web-port
env:
- name: NODE_ENV
valueFrom:
......
......@@ -3,9 +3,9 @@ kind: Deployment
metadata:
name: web-deployment
spec:
replicas: 2
replicas: 1
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
\ No newline at end of file
maxUnavailable: 0
......@@ -18,4 +18,4 @@ patches:
images:
- name: REGISTRY/NAMESPACE/IMAGE:TAG
newName: mmc-registry.cn-shenzhen.cr.aliyuncs.com/sharefly-dev/web
newTag: 6a106c3db8bec076ee249d2f97e575522949a1b1
newTag: 89ba34b307547ad0928c625c100f535432479e78
......@@ -27,7 +27,6 @@ const UserProvider = ({ children }: Props) => {
useEffect(() => {
try {
setUserInfo(JSON.parse(window.localStorage.getItem('userInfo') || '') || undefined);
window.setUserInfo = setUserInfo;
window.setNeedLogin = setNeedLogin;
window.logout = logout;
......
......@@ -27,8 +27,8 @@ const nextConfig = {
return [
{
source: '/local/:path*',
destination: 'https://www.iuav.shop/:path*',
// destination: 'https://test.iuav.shop/:path*',
// destination: 'https://www.iuav.shop/:path*',
destination: 'https://test.iuav.shop/:path*',
},
];
},
......
......@@ -4,8 +4,8 @@ export interface CooperationApplyParams {
applyName: string;
applyPhone: string;
remark?: string;
userAccountId: number;
cooperationTagId: number;
attachmentList?: { type: number; url: string }[];
}
export interface GetTagIdResp {
......@@ -14,6 +14,7 @@ export interface GetTagIdResp {
tagImg: string;
tagDescription: string;
createTime: string;
tagRequire: string;
}
export default {
......
.banner {
width: 100vw;
height: 200px;
background: #f25834;
position: absolute;
left: 50%;
top: 0;
transform: translate(-50%, 0);
.headerLine{
height: 8px;
background: linear-gradient(90deg, #F5B351 0%, #FF552D 100%);
}
.font1 {
font-size: 20px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #000000;
line-height: 25px;
}
.font2 {
font-size: 18px;
font-family: MicrosoftYaHei;
color: #333333;
line-height: 32px;
font-size: 14px;
color: #1A1B1C;
line-height: 19px;
letter-spacing: 1px;
}
.infoContent{
padding: 29px 0 0 50px;
box-sizing: border-box;
.tip{
.tipTitle{
font-size: 14px;
font-weight: bold;
color: #000000;
line-height: 18px;
margin-bottom: 17px;
}
}
.formWrap{
margin-top: 35px;
.formTitle{
font-size: 14px;
font-weight: bold;
color: #000000;
line-height: 18px;
margin-bottom: 17px;
}
}
.uploadTip{
font-size: 12px;
color: #858687;
line-height: 18px;
margin-bottom: 12px;
}
.uploadOperate{
}
}
.submitOperate{
text-align: center;
margin-top: 69px;
button{
width: 200px;
height: 40px;
border-radius: 6px;
background: linear-gradient(90deg, #FF552D 0%, #FF812D 100%);
font-size: 16px;
color: #FEFFFE;
}
}
......@@ -4,107 +4,149 @@ import { useEffect, useState } from 'react';
import LayoutView from '~/components/layout';
import api from './api';
import styles from './index.module.scss';
import { phoneNumber } from '~/lib/validateUtils';
import { Uploader } from '~/components/uploader';
import JoinModal from '~/components/NavHeader/joinModal';
export default function JoinPolicy() {
const [form] = Form.useForm();
const router = useRouter();
const [content, setContent] = useState(''); //福利内容
const tagId = Number(router.query.tagId);
const [tagId, setTagId] = useState<number>(-1);
useEffect(() => {
if (tagId) {
if (router.query.tagId) {
setTagId(Number(router.query.tagId));
api
.getTagById({
id: tagId,
id: Number(router.query.tagId),
})
.then((res) => {
setContent(res.result?.tagDescription.replaceAll('\n', '<br/>') || '');
setContent(res.result?.tagRequire.replaceAll('\n', '<br/>') || '');
});
}
}, []);
}, [router.query.tagId]);
//提交
const onFinish = (values: any) => {
console.log(values);
const submitApply = () => {
form.validateFields().then((valid) => {
api
.cooperationApply({
...values,
...valid,
cooperationTagId: tagId,
})
.then((res) => {
console.log('提交结果', res);
if (res.code === '200') {
window.messageApi.success('提交成功');
form.resetFields();
setTimeout(() => {
router.push('/');
}, 1500);
}
});
});
};
//上传变更
const uploadChange = (value: any) => {
let attachmentList = value.map((v: any) => ({
type: v.type.includes('image') ? 0 : 1,
url: v.url,
}));
form.setFieldValue('attachmentList', attachmentList);
};
return (
<LayoutView>
<div className={styles.banner}></div>
<div
className='page'
style={{
background: '#fff',
position: 'relative',
zIndex: 1,
marginTop: 60,
marginTop: 20,
paddingBottom: 63,
}}
>
<div
className={styles.font1}
style={{ textAlign: 'center', paddingTop: 40, paddingBottom: 30 }}
>
加盟入驻福利
<div className={styles.headerLine}></div>
<div className={styles.font1} style={{ textAlign: 'center', marginTop: '22px' }}>
加盟入驻
</div>
<div
className={styles.font2}
style={{ paddingLeft: 50, paddingRight: 50 }}
dangerouslySetInnerHTML={{ __html: content }}
></div>
<Divider />
<div className={styles.font1} style={{ textAlign: 'center', marginBottom: 28 }}>
申请加盟入驻
<div className={styles.infoContent}>
<div className={styles.tip}>
<div className={styles.tipTitle}>需准备上传资料</div>
<div className={styles.font2} dangerouslySetInnerHTML={{ __html: content }}></div>
</div>
<Row justify={'center'}>
<Col style={{ width: 400 }}>
<Form labelAlign='left' labelCol={{ span: 5 }} onFinish={onFinish}>
<Form.Item label='姓名' name='applyName' rules={[{ required: true }]}>
<Input placeholder='请输入姓名'></Input>
<div className={styles.formWrap}>
<div className={styles.formTitle}>填写资料</div>
<div className={styles.form}>
<Form labelCol={{ span: 2 }} wrapperCol={{ span: 10 }} labelAlign='left' form={form}>
<Form.Item
label='联系人'
name='applyName'
rules={[{ required: true, message: '请输入联系人' }]}
>
<Input placeholder='请输入联系人' maxLength={30} />
</Form.Item>
<Form.Item
label='联系方式'
name='applyPhone'
rules={[
{ required: true },
{
pattern: /^1\d{10}$/,
message: '很输入11位手机号',
},
{ required: true, message: '请输入联系方式' },
{ pattern: /^1\d{10}$/, message: '请输入正确的手机号码' },
]}
>
<Input placeholder='请输入手机号' maxLength={11} onInput={phoneNumber}></Input>
<Input placeholder='请输入联系方式' />
</Form.Item>
<Form.Item name='remark'>
<Input.TextArea placeholder='其它信息'></Input.TextArea>
</Form.Item>
<Row justify={'center'}>
<Button
type='primary'
htmlType='submit'
style={{ marginTop: 11, width: 200 }}
size='large'
<Row>
<Col span={2}>
<div>上传资料:</div>
</Col>
<Col span={10}>
<div className={styles.uploadTip}>
<div>1. 图片格式为JPG、JPEG、BMP、GIF、PNG</div>
<div>2. 文档格式为word、PDF、excel</div>
<div> 3. 文件大小不超过10M</div>
</div>
<div className={styles.uploadOperate}>
<Form.Item name='attachmentList'>
<Uploader
fileUpload
listType='text'
fileLength={10}
fileSize={10}
onChange={uploadChange}
fileType={[
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.ms-excel',
'application/pdf',
'application/msword',
'image/png',
'image/jpeg',
'image/jpg',
'image/gif',
'image/bmp',
]}
>
提交申请
</Button>
</Row>
</Form>
<Button>上传文件</Button>
</Uploader>
</Form.Item>
</div>
</Col>
</Row>
<Form.Item label='备注(选填)' name='remark'>
<Input placeholder='请输入备注' maxLength={60} />
</Form.Item>
</Form>
</div>
</div>
</div>
<div className={styles.submitOperate}>
<Button type='primary' onClick={submitApply}>
提交申请
</Button>
</div>
</div>
</LayoutView>
);
}
JoinPolicy.getInitialProps = async () => {
return {};
};
......@@ -214,7 +214,7 @@ export default function EquipmentLeasingDetail() {
<span className='menoy-right'>/天起</span>
</div>
) : (
<div className='menoy'>暂无报价</div>
<div className='menoy'>获取报价</div>
)}
<div className='classification'>
......
......@@ -19,7 +19,7 @@ interface PropsBox {
export default function OrderForGoods(props: PropsBox) {
const { setIsorderForGoods, shopDetail, days, detailData, wareSkuList, discount } = props;
const [value, setValue] = useState(1);
const [value, setValue] = useState(-1);
const [areaValue, setAreaValue] = useState<string>();
const [list, setList] = useState<Array<UserAddress> | null>();
const [detail, setDetail] = useState<ShopDetail>();
......@@ -33,9 +33,7 @@ export default function OrderForGoods(props: PropsBox) {
};
const detailSumbit = () => {
if (!list?.length) return message.warning('暂无地址信息,请前往云享飞添加地址');
console.log(value !== 0);
if (list?.length && !value && value !== 0) return message.warning('请选择地址');
if (value === -1) return message.warning('请选择地址');
if (detailData && shopDetail && list?.length && wareSkuList) {
const pushList = {
actualPay: discount?.specPrice[0]?.price! * shopDetail?.num! * days! || 0,
......@@ -83,11 +81,8 @@ export default function OrderForGoods(props: PropsBox) {
.then((res) => {
console.log(res);
setList(res.result);
res.result?.map((item, index) => {
if (item.type === 0) {
let index: number = res.result?.findIndex((item) => item.type === 0) as number;
setValue(index);
}
});
})
.catch((err) => {
console.log(err);
......
import { Pagination } from 'antd';
import { Pagination, Image as AntdImage } from 'antd';
import Image from 'next/image';
import { useRouter } from 'next/router';
import { useContext, useEffect, useRef, useState } from 'react';
......@@ -47,7 +47,7 @@ export default function EquipmentLeasing(props: Props) {
<span className='unit'>/天起</span>
</div>
) : (
<div className='unit'>暂无报价</div>
<div className='unit'>获取报价</div>
)}
</div>
</div>
......@@ -57,7 +57,7 @@ export default function EquipmentLeasing(props: Props) {
const rightDom = (item: { id: number; bannerImg: string }) => {
return (
<div key={item.id} className='right-box-item right-item'>
<Image src={item.bannerImg} alt='error' fill />
<AntdImage src={item.bannerImg} width={180} preview={false} />
</div>
);
};
......
......@@ -67,11 +67,6 @@ export const Box = styled.div`
}
.right-item {
width: 180px;
height: 347px;
background: #d8d8d8;
border-radius: 6px;
overflow: hidden;
position: relative;
}
.pagination-page {
text-align: right;
......
......@@ -9,6 +9,7 @@ import {
Select,
Space,
message,
Image as AntdImage,
} from 'antd';
import type { CheckboxValueType } from 'antd/es/checkbox/Group';
import Image from 'next/image';
......@@ -94,7 +95,7 @@ export default function FlyingHandService() {
const rightDom = (item: string) => {
return (
<div className='right-box-item right-item' key={item}>
<Image src={item} alt='error' fill />
<AntdImage src={item} width={260} preview={false} />
</div>
);
};
......
......@@ -128,11 +128,6 @@ export const Box = styled.div`
}
.right-item {
width: 260px;
height: 500px;
background: #ffffff;
border-radius: 6px;
overflow: hidden;
position: relative;
}
.pagination-page {
text-align: right;
......
......@@ -15,9 +15,9 @@ export interface Dynamic {
lat: number;
lon: number;
mediaVO: {
picture: string[];
videoUrl: string;
};
type: number;
url: string;
}[];
likesCount: number;
commentCount: number;
likes: boolean;
......@@ -40,22 +40,24 @@ export interface CommentParams {
content: string; //评论内容
dynamicId: number; //动态id
parentId?: number; //父级评论
rootPath: string;
}
export interface ByDynamicResp {
id: number;
dynamicId: number;
parentId: number;
userId: number;
content: string;
description: string;
likesCount: number;
createTime: string;
dynamicPublishTime: string;
children: ByDynamicResp[];
userBaseInfoVO: {
userBaseInfo: {
id: number;
nickName: string;
userImg: string;
};
mediaVO: { type: number; url: string };
}
export interface dynamicDetail extends ByDynamicResp {
commentAndReplyVO: ByDynamicResp[];
}
export default {
......@@ -73,9 +75,9 @@ export default {
return request('/release/dynamic/comment', 'post', params);
},
//根据动态查看评论
byDynamic(params: { dynamicId: number }): Promise<Response<Array<ByDynamicResp>>> {
return request('/release/dynamic/byDynamic', 'get', params);
//动态详情
byDynamic(params: { dynamicId: number }): Promise<Response<dynamicDetail>> {
return request('/release/dynamic/dynamicDetails', 'get', params);
},
//点赞或取消点赞
......
......@@ -5,10 +5,7 @@ export interface PublishParams {
lon?: number; //经度
description: string; //描述
userId: number; //用户id
mediaVO: {
//发布图片
picture: Array<string>;
};
mediaVO: { type: number; url: string }[];
}
export default {
......
.mediaContent{
display: flex;
align-items: center;
flex-wrap: wrap;
.mediaItemWrap{
position: relative;
.mediaItem{
margin-right: 10px;
margin-bottom: 10px;
}
.mediaDelete{
position: absolute;
right: 0;
top: 0;
transform: translate(0%,-50%);
}
}
}
import { PlusOutlined } from '@ant-design/icons';
import { Form, Input, Modal, Upload, Image, Button, Row, Col } from 'antd';
import type { RcFile, UploadProps } from 'antd/es/upload';
import type { UploadProps } from 'antd/es/upload';
import type { UploadFile } from 'antd/es/upload/interface';
import { useContext, useEffect, useState } from 'react';
import gApi from '~/api';
......@@ -8,7 +7,9 @@ import NImage from 'next/image';
import api from './api';
import { useGeolocation } from '~/lib/hooks';
import { UserContext } from '~/lib/userProvider';
import { useToken } from 'antd/es/theme/internal';
import uploadImg from '~/assets/images/upload.png';
import deleteIcon from '~/assets/images/delete-icon.png';
import styles from './index.module.scss';
type Props = {
open: boolean;
......@@ -25,10 +26,6 @@ const normFile = (e: any) => {
};
export default function PublishMessage(props: Props) {
const [confirmLoading, setConfirmLoading] = useState(false);
const [previewOpen, setPreviewOpen] = useState(false);
const [previewImage, setPreviewImage] = useState('');
const [previewTitle, setPreviewTitle] = useState('');
const [fileList, setFileList] = useState<UploadFile[]>([]);
const [showLoading, setShowLoad] = useState(false);
const [form] = Form.useForm();
......@@ -39,22 +36,28 @@ export default function PublishMessage(props: Props) {
useEffect(() => {
setToken(window.localStorage.getItem('token') || '');
}, []);
//预览关闭
const handlePreviewCancel = () => setPreviewOpen(false);
//图片预览
const handlePreview = async (file: UploadFile) => {
if (file.url) {
setPreviewImage(file.url);
setPreviewOpen(true);
setPreviewTitle(file.name || file.url!.substring(file.url!.lastIndexOf('/') + 1));
}
};
//图片上传
const handleChange: UploadProps['onChange'] = (info) => {
console.log('uploadChange', info);
const isSize = (info.file as any).size / 1024 / 1024 < 5;
if (!isSize) {
window.messageApi.error('上传文件最大5M');
return;
}
const isType = [
'video/mp4',
'video/avi',
'video/wmv',
'video/rmvb',
'image/png',
'image/jpeg',
'image/jpg',
'image/gif',
'image/bmp',
].includes(info.file.type as string);
if (!isType) {
window.messageApi.error('上传文件类型错误');
return;
}
if (info.file.status === 'uploading') {
let find = fileList.find((item) => {
return item.uid === info.file.uid;
......@@ -64,11 +67,10 @@ export default function PublishMessage(props: Props) {
}
return;
} else if (info.file.status === 'done') {
// Get this url from response in real world.
if (info.file.response.code === '200' && info.file.response.result) {
let fileList1 = fileList.map((item) => {
if (item.uid === info.file.uid) {
info.file.url = info.file.response.result?.[0];
info.file.url = info.file.response.result;
return info.file;
}
return item;
......@@ -85,10 +87,13 @@ export default function PublishMessage(props: Props) {
setFileList([...info.fileList]);
}
};
//删除媒体
const deleteMedia = (file: UploadFile) => {
let list = fileList.filter((v) => v.uid !== file.uid);
setFileList(list || []);
};
//提交
const onFinish = (values: any) => {
console.log(values);
setShowLoad(true);
if (userInfo) {
......@@ -96,39 +101,39 @@ export default function PublishMessage(props: Props) {
.publish({
lat: position?.position?.lat, //纬度
lon: position?.position?.lng, //经度
title: '', //标题
description: values.description, //描述
userId: userInfo.id, //用户id
mediaVO: {
//发布图片
//@ts-ignore
picture: fileList.filter((item) => item.url).map((item) => item.url),
},
mediaVO: fileList.map((item) => ({
type: item.type?.includes('image') ? 0 : 1,
url: item.url as string,
})),
})
.then((res) => {
console.log('提交结果', res);
setShowLoad(false);
if (res.code === '200') {
window.messageApi.success('发布成功');
props.onCancel();
props.onOk && props.onOk();
setTimeout(() => {
form.resetFields(['title', 'description']);
form.resetFields();
setFileList([]);
}, 500);
}
});
}
};
//取消
const handleCancel = () => {
form.resetFields();
setFileList([]);
props.onCancel();
};
return (
<Modal
title=''
open={props.open}
onCancel={props.onCancel}
onCancel={handleCancel}
width={500}
confirmLoading={confirmLoading}
footer={null}
okButtonProps={{ style: { height: 37, padding: '0 32px', fontSize: 16 } }}
cancelButtonProps={{ style: { display: 'none' } }}
......@@ -140,38 +145,63 @@ export default function PublishMessage(props: Props) {
allowClear
showCount
placeholder='输入内容'
maxLength={100}
maxLength={256}
style={{ height: 120, resize: 'none' }}
></Input.TextArea>
</Form.Item>
<Row style={{ marginTop: '10px' }}>
{fileList.length ? (
<Col>
<div className={styles.mediaContent}>
{fileList.map((v, index: number) => (
<div className={styles.mediaItemWrap} key={index}>
<div className={styles.mediaItem}>
{v.type?.includes('image') ? (
<Image
src={v.url}
width={100}
height={100}
alt=''
style={{ verticalAlign: 'top' }}
/>
) : (
<video src={v.url} style={{ width: '100px', height: '100px' }} controls />
)}
</div>
<NImage
src={deleteIcon}
alt=''
className={styles.mediaDelete}
width={20}
height={20}
onClick={() => deleteMedia(v)}
/>
</div>
))}
</div>
</Col>
) : (
''
)}
<Col>
<Form.Item valuePropName='picture' getValueFromEvent={normFile}>
<Upload
name='uploadFile'
action={gApi.imgOss}
action={gApi.fileUpload}
listType='picture-card'
fileList={fileList}
onPreview={handlePreview}
onChange={handleChange}
showUploadList={false}
maxCount={1}
headers={{ token: token }}
>
{fileList.length >= 8 ? null : (
<div>
<PlusOutlined />
<div style={{ marginTop: 8 }}>Upload</div>
</div>
{fileList.length >= 9 ? null : (
<NImage src={uploadImg} alt='' width={100} height={100} />
)}
</Upload>
<Modal
open={previewOpen}
title={previewTitle}
footer={null}
onCancel={handlePreviewCancel}
bodyStyle={{ textAlign: 'center' }}
>
<Image alt='example' src={previewImage} preview={false} />
</Modal>
</Form.Item>
</Col>
</Row>
<Row justify='space-between' align='middle'>
<Col>
<NImage
......
......@@ -60,6 +60,7 @@
margin-bottom: 16px;
padding-right: 10px;
line-height: 1.2;
word-break: break-all;
}
}
......
......@@ -81,7 +81,7 @@ export default function Forum() {
})
.then((res) => {
if (res?.code === '200') {
item.commentList = res.result || [];
item.commentList = res.result?.commentAndReplyVO || [];
}
const temp = [...list];
setList(temp);
......@@ -102,6 +102,7 @@ export default function Forum() {
.comment({
content: values.content,
dynamicId: item.id,
rootPath: item.id.toString(),
})
.then((res) => {
if (res.code === '200') {
......@@ -169,28 +170,41 @@ export default function Forum() {
<div className={styles.name}>{item.userBaseInfo?.nickName}</div>
<div className={styles.desc}>{item.description}</div>
<div className={styles.imgs}>
<Image.PreviewGroup
preview={{
onChange: (current, prev) =>
console.log(`current index: ${current}, prev index: ${prev}`),
}}
>
<Space size={6} wrap>
{item?.mediaVO?.picture?.map((img) => {
return (
{item?.mediaVO?.map((v, index: number) =>
v.type === 0 ? (
<Image
key={img}
key={index}
alt=''
className='img'
width={132}
height={132}
src={img}
src={v.url}
fallback={errImg}
/>
);
})}
) : (
<video
key={index}
src={v.url}
controls
style={{ width: '132px', height: '132px' }}
/>
),
)}
</Space>
</Image.PreviewGroup>
{/*<Image.PreviewGroup*/}
{/*>*/}
{/* <Space size={6} wrap>*/}
{/* {item?.mediaVO*/}
{/* ?.filter((v) => v.type === 0)*/}
{/* ?.map((img, index: number) => {*/}
{/* return (*/}
{/* );*/}
{/* })}*/}
{/* </Space>*/}
{/*</Image.PreviewGroup>*/}
</div>
<div className={styles.ctrls}>
<div className={styles.ctrlsItem} onClick={() => openComment(item)}>
......@@ -253,17 +267,19 @@ export default function Forum() {
return (
<div key={comment.id} className={styles.commentItem}>
<div className={styles.commentHeadImg}>
<Image src={comment.userBaseInfoVO?.userImg}></Image>
<Image src={comment.userBaseInfo?.userImg}></Image>
</div>
<div className={styles.info}>
<div className={styles.nameWrap}>
<div className={styles.commentName}>
{comment.userBaseInfoVO?.nickName}
{comment.userBaseInfo?.nickName}
<div className={styles.date}>
{moment(comment.createTime).format('YYYY-MM-DD')}
{moment(comment.dynamicPublishTime).format('YYYY-MM-DD')}
</div>
</div>
<div className={styles.commentContent}>
{comment.description}
</div>
<div className={styles.commentContent}>{comment.content}</div>
</div>
</div>
</div>
......
......@@ -116,6 +116,7 @@ export interface NewsTenderType {
tenderPrice: number;
createTime: string;
apply: number;
tenderTitle: string;
}
export interface ListPageNewsInfoResp {
......
......@@ -17,6 +17,7 @@ import api, {
listNewsApi,
mallApi,
} from './api';
import { bigNumberTransform } from '~/utils/money';
interface ColumnsType {
title: string;
......@@ -428,15 +429,15 @@ export default function WaterfallFlowBody() {
<div className='body'>
{list?.map((item) => (
<div key={item.id} className='body-item'>
<div className='item-label' title={item.tenderContent}>
{item.tenderContent}
<div className='item-label' title={item.tenderTitle}>
{item.tenderTitle}
<div className='label-bottom'>{item.tenderPrice}</div>
</div>
<div
className={`item-right ${item.apply ? 'apply' : ''}`}
onClick={() => handleTenderApply(item)}
>
<div className='left'>{`${item.tenderPrice}W`}</div>
<div className='left'>{bigNumberTransform(item.tenderPrice * 10000, true)}</div>
{item.apply ? (
<div className='right'>已申请</div>
) : (
......
......@@ -294,12 +294,12 @@ export const Box = styled.div`
height: 22px;
line-height: 22px;
font-size: 11px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #ff4500;
text-align: center;
left: 4px;
top: 0;
white-space: nowrap;
}
.right {
width: 48px;
......
import React, { useEffect, useState, useRef } from 'react';
import { Box } from './styled';
import { Pagination } from 'antd';
import { Pagination, Image } from 'antd';
import Layout from '~/components/layout';
import ContentBox from '~/components/contentBox';
import { useRouter } from 'next/router';
import Filter, { FilterResult, AdapterResult } from '~/components/filter';
import api, { Job } from './api';
import commonApi from '~/api';
import Image from 'next/image';
// 此函数在构建时被调用
export async function getServerSideProps() {
return {
......@@ -53,7 +52,7 @@ export default function JobServices() {
const rightDom = (item: string) => {
return (
<div className='right-box-item advertisement' key={item}>
<Image src={item} alt='error' width={260} height={500} />
<Image src={item} width={260} preview={false} />
</div>
);
};
......
......@@ -86,12 +86,6 @@ export const Box = styled.div`
}
}
}
.advertisement {
width: 260px;
height: 420px;
background: #ffffff;
border-radius: 6px;
}
.pagination-page {
text-align: right;
}
......
......@@ -24,20 +24,21 @@ interface PropsBox {
export default function OrderForGoods(props: PropsBox) {
const { setIsorderForGoods, shopDetail, detailData, wareSkuList, discount, mallDetail } = props;
const [value, setValue] = useState(1);
const [value, setValue] = useState(0);
const [areaValue, setAreaValue] = useState<string>();
const [list, setList] = useState<Array<UserAddress> | null>();
const onChange = (e: RadioChangeEvent) => {
console.log('radio checked', e.target.value);
console.log('数据-->', e.target.value);
setValue(e.target.value);
};
const onChangeValue = (index: number) => {
setValue(index);
const onChangeValue = (id: number) => {
console.log('数据id-->', id);
setValue(id);
};
const detailSumbit = () => {
if (!list?.length) return message.warning('暂无地址信息,请前往云享飞添加地址');
if (list?.length && !value && value !== 0) return message.warning('请选择地址');
if (!value) return message.warning('请选择地址');
if (detailData && list && mallDetail) {
const pushList = {
buyNum: mallDetail.buyNum,
......@@ -246,7 +247,11 @@ export default function OrderForGoods(props: PropsBox) {
</div>
<div className='bottom'>
<div className='value'>寄送至</div>
{list ? <div className='value-content'>{list![value]?.takeAddress}</div> : null}
{list ? (
<div className='value-content'>
{list![list.findIndex((v) => v.id === value)]?.takeAddress}
</div>
) : null}
</div>
</div>
<div className='detail-sumbit'>
......
......@@ -151,7 +151,7 @@ export default function Mall(props: Props) {
className={styles.ad}
src={item.bannerImg}
width={189}
height={364}
// height={364}
preview={false}
fallback={errImg}
></Image>
......
import { RightOutlined } from '@ant-design/icons';
import { Col, Row, Space, Image } from 'antd';
import { Col, Row } from 'antd';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
import errImg from '~/assets/errImg';
import Layout from '~/components/layout';
import newsApi, { Item } from '../components/news/api';
import api, { DetailsResp } from './api';
......@@ -70,11 +69,12 @@ export default function CaseArticle() {
<Col flex='auto'>
<div className={styles.font1}>{data?.caseTitle}</div>
<div className={styles.font2} style={{ marginTop: 18, marginBottom: 41 }}>
{data?.createTime && Moment(data?.createTime).format('YYYY-MM-DD')} ·{' '}
{data?.caseAuthor}
{data?.createTime && Moment(data?.createTime).format('YYYY-MM-DD')} ·作者:
{data?.caseAuthor || '不详'}
</div>
<div
style={{ lineHeight: 1.5 }}
className={styles.richText}
dangerouslySetInnerHTML={{ __html: data?.caseContents || '' }}
></div>
</Col>
......
......@@ -37,3 +37,9 @@
.ellipse1 {
@include ellipsis(1);
}
.richText{
img{
max-width: 100%;
height: auto;
}
}
......@@ -25,6 +25,7 @@ export interface Item {
tenderPrice: number;
createTime: string;
apply: 0 | 1;
tenderTitle: string;
}
export interface ApplyParams {
......
......@@ -8,7 +8,14 @@
border-bottom: 1px dashed RGBA(222, 222, 222, 1);
justify-content: space-between;
align-items: center;
cursor: pointer;
&:hover {
.info{
.title{
color: red;
}
}
}
.info {
.title {
font-size: 14px;
......
......@@ -3,6 +3,8 @@ import { useState, useEffect, useContext } from 'react';
import { UserContext } from '~/lib/userProvider';
import api, { Item } from './api';
import styles from './index.module.scss';
import { bigNumberTransform } from '~/utils/money';
import { useRouter } from 'next/router';
type Props = {
params?: {
......@@ -14,6 +16,7 @@ type Props = {
};
export default function Bids(props: Props) {
const router = useRouter();
const [list, setList] = useState<Array<Item>>([]);
const [pageParams, setPageParams] = useState({
pageNo: 1,
......@@ -78,24 +81,32 @@ export default function Bids(props: Props) {
setNeedLogin(true);
}
};
//招标项目详情
const toTenderProjectsDetail = (item: Item) => {
router.push('/projectInfo/tenderProjectsDetail/' + item.id);
};
return (
<Spin spinning={loading} delay={500}>
<div className={styles.bids} style={{ height: 610 }}>
{list.map((item) => {
return (
<div className={styles.item} key={item.id}>
<div className={styles.item} key={item.id} onClick={() => toTenderProjectsDetail(item)}>
<div className={styles.info}>
<div className={styles.title}>{item.tenderContent}</div>
<div className={styles.title}>{item.tenderTitle}</div>
</div>
{item.apply ? (
<Button type='primary' disabled className={`${styles.btn} ${styles.disabled}`}>
<div className={styles.text1}>{item.tenderPrice}</div>
<div className={styles.text1}>
{bigNumberTransform(item.tenderPrice * 10000, true)}
</div>
<div className={styles.text2}>已申请</div>
</Button>
) : (
<Button type='primary' className={styles.btn}>
<div className={styles.text1}>{item.tenderPrice}</div>
<div className={styles.text1}>
{bigNumberTransform(item.tenderPrice * 10000, true)}
</div>
<div className={styles.text2} onClick={() => onApply(item)}>
商务合作
</div>
......
......@@ -9,14 +9,23 @@
border-bottom: 1px dashed RGBA(222, 222, 222, 1);
justify-content: space-between;
align-items: center;
cursor: pointer;
&:hover{
.info{
.title{
color: red;
}
}
}
.info {
flex: 1;
.title {
font-size: 14px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
color: #3c3e42;
width: 649px;
width:100%;
text-overflow: ellipsis;
@include ellipsis(1);
margin-right: 10px;
}
.desc {
font-size: 14px;
......
......@@ -67,14 +67,11 @@ export default function Cases(props: Props) {
return (
<div className={styles.item} key={item.id}>
<div className={styles.info}>
<div className={styles.title}>
<Button
type='link'
style={{ padding: '0 0' }}
<div
className={styles.title}
onClick={() => Router.push('/projectInfo/caseArticle/' + item.id)}
>
{item.caseTitle}
</Button>
</div>
</div>
<Button
......
......@@ -11,7 +11,14 @@
display: flex;
border-bottom: 1px dashed RGBA(222, 222, 222, 1);
align-items: center;
cursor: pointer;
&:hover {
.info{
.title{
color: red;
}
}
}
.logo {
width: 120px;
height: 80px;
......
import { RightOutlined } from '@ant-design/icons';
import { Button, Col, Empty, Pagination, Row, Spin } from 'antd';
import { Col, Empty, Pagination, Row, Spin } from 'antd';
import styles from './index.module.scss';
import Image from 'next/image';
import { useState, useEffect, useContext } from 'react';
import api, { Item } from './api';
import Router from 'next/router';
import Moment from 'moment';
import Router, { useRouter } from 'next/router';
import { UserContext } from '~/lib/userProvider';
type Props = {
......@@ -18,6 +16,7 @@ type Props = {
};
export default function News(props: Props) {
const router = useRouter();
const [loading, setLoading] = useState(false);
const [list, setList] = useState<Array<Item>>([]);
const [pageParams, setPageParams] = useState({
......@@ -74,14 +73,17 @@ export default function News(props: Props) {
setNeedLogin(true);
}
};
//新闻点击
const newsClick = (item: Item) => {
router.push('/projectInfo/newsArticle/' + item.id);
};
return (
<Spin spinning={loading} delay={500}>
<Row justify='space-between' style={{ height: 606 }}>
<Col className={styles.new}>
{list.map((item) => {
return (
<div className={styles.item} key={item.id}>
<div className={styles.item} key={item.id} onClick={() => newsClick(item)}>
<Image
className={styles.logo}
src={item.surfaceImg}
......@@ -91,18 +93,23 @@ export default function News(props: Props) {
></Image>
<div className={styles.info}>
<div className={styles.title}>{item.newsTitle}</div>
<div className={styles.desc}>{item.newsContents}</div>
<div
className={styles.desc}
dangerouslySetInnerHTML={{
__html: item.newsContents.replace(/<img(?:(?!\/>).|\n)*?\/>/gm, '') || '',
}}
></div>
<div className={styles.date}>
{Moment().format('yyyy-MM-DD')} · {item.newsAuthor}
{item.createTime} · 作者:{item.newsAuthor}
</div>
</div>
<Button
type='primary'
style={{ width: 120, height: 40, flexShrink: 0 }}
onClick={onGetInfo}
>
获取产品资料
</Button>
{/*<Button*/}
{/* type='primary'*/}
{/* style={{ width: 120, height: 40, flexShrink: 0 }}*/}
{/* onClick={onGetInfo}*/}
{/*>*/}
{/* 获取产品资料*/}
{/*</Button>*/}
</div>
);
})}
......
.bannerWrap{
height: 100px;
position: relative;
}
......
import { RightOutlined } from '@ant-design/icons';
import { Col, Row, Space, Image } from 'antd';
import { Col, Row } from 'antd';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
import errImg from '~/assets/errImg';
import Layout from '~/components/layout';
import newsApi, { Item } from '../components/news/api';
import api, { DetailsResp } from './api';
......@@ -70,11 +69,12 @@ export default function CaseArticle() {
<Col flex='auto'>
<div className={styles.font1}>{data?.newsTitle}</div>
<div className={styles.font2} style={{ marginTop: 18, marginBottom: 41 }}>
{data?.createTime && Moment(data?.createTime).format('YYYY-MM-DD')} ·{' '}
{data?.newsAuthor}
{data?.createTime && Moment(data?.createTime).format('YYYY-MM-DD')} ·作者:
{data?.newsAuthor || '不详'}
</div>
<div
style={{ lineHeight: 1.5 }}
className={styles.richText}
dangerouslySetInnerHTML={{ __html: data?.newsContents || '' }}
></div>
</Col>
......
......@@ -3,7 +3,6 @@ import request, { Response } from '~/api/request';
export interface DetailsParams {
id: number;
}
export interface DetailsResp {
id: number;
newsTitle?: string;
......
......@@ -37,3 +37,9 @@
.ellipse1 {
@include ellipsis(1);
}
.richText{
img{
max-width: 100%;
height: auto;
}
}
import { RightOutlined } from '@ant-design/icons';
import { Col, Row } from 'antd';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
import Layout from '~/components/layout';
import newsApi, { Item } from '../components/news/api';
import api, { DetailsResp } from './api';
import styles from './index.module.scss';
import Moment from 'moment';
export default function TenderProjectsDetail() {
const router = useRouter();
const [data, setData] = useState<DetailsResp>();
const [newsList, setNewList] = useState<Item[]>([]);
//获取案例详情
useEffect(() => {
const id = Number(router.query.id);
if (id) {
api
.details({
id,
})
.then((res) => {
setData(res.result || undefined);
});
}
}, [router]);
//获取新闻列表
useEffect(() => {
newsApi
.listNewsPage({
pageNo: 1,
pageSize: 10,
})
.then((res) => {
setNewList(res.result?.list || []);
});
}, []);
const fontColor = (i: number) => {
switch (i) {
case 0:
return {
color: '#ff2c46',
};
case 1:
return {
color: '#FF6602',
};
case 2:
return {
color: '#FAA910',
};
default:
return {
color: '#9295A3',
};
}
};
return (
<Layout layoutStyle={{ backgroundColor: '#fff' }}>
<div style={{ paddingTop: 29 }}>
<Row justify='space-between' wrap={false}>
<Col flex='auto'>
<div className={styles.font1}>{data?.tenderTitle}</div>
<div className={styles.font2} style={{ marginTop: 18, marginBottom: 41 }}>
{data?.createTime && Moment(data?.createTime).format('YYYY-MM-DD')}
</div>
<div
style={{ lineHeight: 1.5 }}
className={styles.richText}
dangerouslySetInnerHTML={{ __html: data?.tenderContent || '' }}
></div>
</Col>
<Col>
<div className={styles.newsBox}>
<Row
className={styles.font4}
align='middle'
style={{ paddingTop: 16, paddingLeft: 20 }}
>
行业新闻
<RightOutlined style={{ fontSize: 16, marginLeft: 9 }} />
</Row>
<Row gutter={10} style={{ marginTop: 8 }}>
<Col span={24}>
{newsList.map((item, i) => {
return (
<Row
key={item.id}
justify='space-between'
align='middle'
style={{ cursor: 'pointer' }}
onClick={() => {
router.push('/projectInfo/newsArticle/' + item.id);
}}
>
<Col
className={`${styles.font3}`}
style={{ margin: '6px 23px 6px 19px', width: '100%' }}
>
<Row wrap={false}>
<Col span={2} style={{ textAlign: 'center', ...fontColor(i) }}>
{i + 1}
</Col>
<Col span={22} className={styles.ellipse1}>
{item.newsTitle}
</Col>
</Row>
</Col>
</Row>
);
})}
</Col>
</Row>
</div>
</Col>
</Row>
</div>
</Layout>
);
}
import request, { Response } from '~/api/request';
import { Item } from '~/pages/projectInfo/components/news/api';
export interface DetailsParams {
id: number;
}
export interface DetailsResp {
id: number;
tenderTitle?: string;
tenderPrice?: number;
tenderContent?: string;
createTime?: string;
}
export default {
//招标详情
details(params: DetailsParams): Promise<Response<DetailsResp>> {
return request('/release/tender/infoById', 'get', params);
},
};
@import "~/styles/mixins.scss";
.font1 {
font-size: 36px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #000000;
line-height: 50px;
}
.font2 {
font-size: 12px;
font-family: MicrosoftYaHei;
color: #333333;
line-height: 16px;
}
.font3 {
font-size: 14px;
font-family: MicrosoftYaHei;
color: #323232;
line-height: 19px;
}
.font4 {
font-size: 16px;
font-family: MicrosoftYaHeiUI-Bold, MicrosoftYaHeiUI;
font-weight: bold;
color: #000000;
line-height: 20px;
}
.newsBox {
width: 384px;
}
.ellipse1 {
@include ellipsis(1);
}
.richText{
img{
max-width: 100%;
height: auto;
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
// @ts-nocheck
/* eslint-disable */
export const formatCurrency = (s, n) => {
n = n > 0 && n <= 20 ? n : 2
s = `${parseFloat(`${s}`.replace(/[^\d\.-]/g, '')).toFixed(n)}`
const l = s.split('.')[0].split('').reverse()
const r = s.split('.')[1]
let t = ''
for (let i = 0; i < l.length; i++) {
t += l[i] + ((i + 1) % 3 == 0 && i + 1 != l.length ? ',' : '')
}
return t.split('').reverse().join('')
}
// 格式化千分位并补零
export const moneyFormat = (num) => {
if (Number(num).toString() !== 'NaN') {
// 添加千分符
let _n = Number(num).toLocaleString()
if (_n.indexOf('.') !== -1) {
_n = `${_n}00`
} else {
_n = `${_n}.00`
}
// 因为有千分符所以,返回数据为字符串格式,无法做运算操作,适合做直接显示使用
return _n.substring(0, _n.indexOf('.') + 3)
}
// console.log('参数格式有误')
}
// 金额大数字转换
export const bigNumberTransform = (value, type) => {
const newValue = ['', '', '']
let fr = 1000
let num = 3
let text1 = ''
let text2 = ''
let fm = 1
if (value == '' || value == null || isNaN(value)) {
return !type ? newValue : ''
}
if (value < 0) {
value = Math.abs(value)
text2 = '-'
}
while (value / fr >= 1) {
fr *= 10
num += 1
// console.log('数字', value / fr, 'num:', num)
}
if (num <= 4) {
// 千
newValue[0] = value
newValue[1] = ''
} else if (num <= 8) {
// 万
// text1 = parseInt(num - 4) / 3 > 1 ? '千万' : '万'
text1 = '万'
// tslint:disable-next-line:no-shadowed-variable
fm = text1 === '万' ? 10000 : 10000000
if (value % fm === 0) {
newValue[0] = `${parseInt(value / fm)}`
} else {
newValue[0] = `${parseFloat(value / fm).toFixed(2)}`
}
newValue[1] = text1
} else {
// 亿 if (num <= 16)
// text1 = (num - 8) / 3 > 1 ? '千亿' : '亿'
text1 = '亿'
text1 = (num - 8) / 4 > 1 ? '万亿' : text1
text1 = (num - 8) / 7 > 1 ? '千万亿' : text1
text1 = (num - 8) / 10 > 1 ? '亿亿' : text1
// tslint:disable-next-line:no-shadowed-variable
fm = 1
if (text1 === '亿') {
fm = 100000000
} else if (text1 === '千亿') {
fm = 100000000000
} else if (text1 === '万亿') {
fm = 1000000000000
} else if (text1 === '千万亿') {
fm = 1000000000000000
} else {
fm = 1000000000000000000
}
if (value % fm === 0) {
newValue[0] = `${parseInt(value / fm)}`
} else {
newValue[0] = `${parseFloat(value / fm).toFixed(2)}`
}
newValue[1] = text1
}
if (value < 1000) {
newValue[0] = `${value}`
newValue[1] = ''
}
newValue[0] = text2 ? text2 + newValue[0] : newValue[0]
return !type ? newValue : newValue[0] + newValue[1]
}
// 格式化金额
export const formatMoney = (money) => {
return money?.toLocaleString()
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论