Commit 8634de87 authored by 武广's avatar 武广

feat: 添加属性组件

parent 946cea22
const isProduction = process.env.NODE_ENV === 'production';
const isPre = process.env.PRE_ENV === 'pre';
const environment = 'sc';
const environment = 'xyqb';
const envAPi = {
api: `https://security-${environment}.liangkebang.net`, //'https://security-xyqb.liangkebang.net',
kdspOpApi: `https://sc-merchant-api-${environment}.liangkebang.net`,
......
import React, { useEffect, useRef, useState } from 'react';
import { Select, Space, Divider, Input, Button } from 'antd';
import { PlusOutlined } from '@ant-design/icons';
const CustomSelect = props => {
const [name, setName] = useState('');
const [items, setItems] = useState([]);
const inputRef = useRef(null);
const onNameChange = e => {
setName(e.target.value);
};
const addItem = e => {
e.preventDefault();
const v = name.trim();
if (v) {
setItems([...items, { name: v }]);
setName('');
setTimeout(() => {
// eslint-disable-next-line no-unused-expressions
inputRef.current?.focus();
}, 0);
}
};
const onChange = e => {
props.onChange(e);
};
useEffect(() => {
setItems(props.options);
}, [props.options]);
return (
<Select
mode={props.mode}
maxTagTextLength={8}
allowClear
value={props.value}
onChange={onChange}
dropdownRender={menu => (
<>
{menu}
{props.isCustom && (
<>
<Divider style={{ margin: '8px 0' }} />
<Space style={{ padding: '0 8px 4px' }}>
<Input
placeholder="请输入自定义属性"
ref={inputRef}
value={name}
onChange={onNameChange}
/>
<Button type="text" icon={<PlusOutlined />} onClick={addItem} />
</Space>
</>
)}
</>
)}
options={items.map(item => ({ label: item.name, value: JSON.stringify(item) }))}
></Select>
);
};
export default CustomSelect;
......@@ -56,7 +56,7 @@ class goodsManage extends Component {
stockSkuIds: [],
isType: '',
serviceVisble: false,
serviceVisble: true,
serviceData: {},
visibleAuditModal: false,
auditRow: {}, // 查看审核信息使用
......@@ -405,30 +405,29 @@ class goodsManage extends Component {
this.canEditable = permissions[GOOD_MANAGE.EDITABLE];
return (
<PageHeaderWrapper>
{canAddNormal || canAddService ? (
<Button
type="primary"
className={styles.button}
onClick={() => this.serviceVisbleClose(true)}
>
新增商品
</Button>
) : (
''
)}
{/* {canAddService ? (
<Button
type="primary"
className={styles.button}
onClick={() => this.serviceVisbleClose(true)}
>
新增服务类商品
</Button>
) : (
''
)} */}
<Spin spinning={this.state.createloading}>
{canAddNormal ? (
<Button
type="primary"
className={styles.button}
onClick={() => this.setState({ createVisible: true, initData: {} })}
>
新增商品
</Button>
) : (
''
)}
{canAddService ? (
<Button
type="primary"
className={styles.button}
onClick={() => this.serviceVisbleClose(true)}
>
新增服务类商品
</Button>
) : (
''
)}
<Card>
<SearchForm
handleSearch={this.handleSearch}
......@@ -539,6 +538,7 @@ class goodsManage extends Component {
categoryList={this.state.treeData}
virtualCategoryList={this.state.virtualTreeData}
specListData={this.state.specListData}
permissions={permissions}
/>
</Spin>
<InfoAudit
......
......@@ -164,3 +164,13 @@
}
}
}
.attrbox {
max-height: 384px;
overflow: hidden;
}
.attrboxMore {
max-height: max-content;
}
.btnMore {
text-align: center;
}
/* eslint-disable consistent-return */
import React, { forwardRef, useContext, useState, useEffect, useImperativeHandle } from 'react';
import { Form, Select, Row, Col, Button } from 'antd';
import { UpOutlined, DownOutlined } from '@ant-design/icons';
import { ServiceContext } from '../context';
import styles from '../common.less';
import { apiGetAttribute } from '../service';
import CustomSelect from '@/components/CustomSelect';
const FormAttr = forwardRef((props, ref) => {
const customer = useContext(ServiceContext);
const [form] = Form.useForm();
const [isMore, setIsMome] = useState(false);
const [categoryAttrs, setCategoryAttrs] = useState([]);
const [skuOldAttr, setSkuOldAttr] = useState([]);
const formItemAttr = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
const onChangeMore = () => {
setIsMome(!isMore);
};
// 获取属性
const getAttribute = async categoryId => {
const res = await apiGetAttribute(categoryId);
if (res && res.data && res.data.length) {
setCategoryAttrs(res.data);
}
};
// 验证是否失效属性(已失效的商品不显示)
const checkInAttrList = id => categoryAttrs.some(item => item.valueList.some(v => +v.id === +id));
// 获取初始化属性数据
const getInitAttrValue = () => {
const skuAttr = props.initData.productAttributeApplyList?.productAttributeApplyList || [];
const attrs = [];
if (customer.isEdit) {
categoryAttrs.forEach(({ id, supportCustomValue, optionType }) => {
const v = skuAttr.filter(item => id === item.productAttributeId);
let values = '';
const key = 'productAttributeApplyValueList';
if (v.length && v[0][key] && v[0][key].length) {
values = [];
if (+supportCustomValue.code === 1 || +optionType.code === 2) {
v[0][key].forEach(attr => {
if (+attr.attributeValueId) {
checkInAttrList(attr.attributeValueId) &&
values.push(
JSON.stringify({
attributeValueId: attr.attributeValueId,
attributeValueName: attr.attributeValueName,
}),
);
} else {
values.push(attr.attributeValueName);
}
});
} else if (v[0][key].length) {
const atvalue = v[0][key][0];
if (checkInAttrList(atvalue.attributeValueId)) {
values = JSON.stringify({
attributeValueId: atvalue.attributeValueId,
attributeValueName: atvalue.attributeValueName,
});
}
}
}
attrs.push({
[id]: values,
});
});
}
return attrs;
};
const getMode = optionType => {
if (+optionType.code === 2) {
return 'multiple';
}
return 'default';
};
const getAttrRules = k => {
if (+k.required.code === 1) {
return [
{
required: true,
type: +k.supportCustomValue.code === 1 || +k.optionType.code === 2 ? 'array' : 'string',
message: '请选择',
},
];
}
return [];
};
const deal = attr => {
try {
const json = JSON.parse(attr);
if (typeof json === 'object' && checkInAttrList(json.attributeValueId)) {
return json;
}
return { attributeValueName: json };
} catch {
return { attributeValueName: attr };
}
};
const onCheck = async () => {
try {
const values = await form.validateFields();
const attributeApplyList = [];
// eslint-disable-next-line no-restricted-syntax
for (const key in values) {
if (values.hasOwnProperty(key)) {
let attrs = values[key];
if (Array.isArray(values[key])) {
attrs = [];
values[key].forEach(attr => {
const json = deal(attr);
json && attrs.push(json);
});
} else {
const json = deal(values[key]);
json && (attrs = [json]);
}
attributeApplyList.push({
attributeId: key,
attributeApplyValueList: attrs,
});
}
}
const v = {
temp: 'attributeApplyList',
attributeApplyList,
};
return v;
} catch (errorInfo) {
return null;
}
};
useEffect(() => {
const ids = props.categoryIds;
if (ids && ids.length) {
getAttribute(ids[ids.length - 1]);
}
}, [props.categoryIds]);
useEffect(() => {
if (props.editData && props.editData.productAttributeApplyList?.oldProductAttributeApplyList) {
const oattr = props.editData.productAttributeApplyList;
setSkuOldAttr((oattr && oattr.oldProductAttributeApplyList) || []);
}
}, [props.editData]);
useImperativeHandle(ref, () => ({
onCheck,
reset: form.resetFields,
}));
return (
<>
<div className={styles.attrbox + (isMore ? styles.attrboxMore : '')} more={isMore}>
<Form form={form} initialValues={getInitAttrValue()}>
<Row>
{categoryAttrs.length > 0 &&
categoryAttrs.map(k => (
<Col span={12} key={k.id}>
<Form.Item
label={k.name}
name={k.id}
{...formItemAttr}
key={k.id}
rules={getAttrRules(k)}
>
<CustomSelect
options={k.valueList || []}
isCustom={+k.supportCustomValue.code === 1}
mode={getMode(k.optionType)}
/>
</Form.Item>
</Col>
))}
</Row>
</Form>
</div>
{categoryAttrs.length > 12 && (
<div className={styles.btnMore}>
<Button type="link" onClick={onChangeMore}>
{isMore ? (
<>
收起 <UpOutlined />
</>
) : (
<>
展示更多 <DownOutlined />
</>
)}
</Button>
</div>
)}
{skuOldAttr.length > 0 && (
<div>
<Row>注:以下商品属性已失效,请使用新的属性</Row>
<Row>
{skuOldAttr.map(s => (
<Col span={12} key={s.id}>
<Form.Item
label={s.productAttributeName}
{...formItemAttr}
required={false}
key={s.id}
>
{s.productAttributeApplyValueList.map(item => item.attributeValueName).join('')}
</Form.Item>
</Col>
))}
</Row>
</div>
)}
</>
);
});
export default FormAttr;
......@@ -95,6 +95,7 @@ const FormInformationBasic = forwardRef((props, ref) => {
placeholder="请选择商品类目!"
showSearch={{ filter: filterCategoryOptions }}
fieldNames={{ label: 'name', value: 'id', children: 'children' }}
onChange={e => props.onCategoryChange(e)}
options={newCategoryList[customer.productType]}
/>
</Form.Item>
......
......@@ -15,6 +15,9 @@ const FormRuleVPictures = forwardRef((props, ref) => {
const [form] = Form.useForm();
const customer = useContext(ServiceContext);
const typeConfig = TaskList(customer.canAddService, customer.canAddNormal);
const [{ imgConfig }] = typeConfig.filter(item => item.type === customer.productType);
useEffect(() => {
if (customer.isEdit) {
if (editData) {
......@@ -104,7 +107,6 @@ const FormRuleVPictures = forwardRef((props, ref) => {
});
};
const [{ imgConfig }] = TaskList.filter(item => item.type === customer.productType);
return (
<Form
form={form}
......
......@@ -5,6 +5,7 @@ import commonStyle from '../common.less';
export const TaskTypeSelect = props => {
const customer = useContext(ServiceContext);
const typeConfig = TaskList(customer.canAddService, customer.canAddNormal);
const selectTabs = task => {
if (!customer.isEdit) {
props.onChange(task);
......@@ -13,7 +14,7 @@ export const TaskTypeSelect = props => {
return (
<div className={commonStyle.prodcutContent}>
{TaskList.map(task => {
{typeConfig.map(task => {
const activeClassName = props.productType === task.type ? commonStyle.activeCard : '';
if (task.hide) return null;
return (
......
......@@ -7,12 +7,12 @@ export const formItemLayout = {
},
};
export const TaskList = [
export const TaskList = (canAddService, canAddNormal) => [
{
name: '实体商品',
type: 1,
desc: '物流发货',
hide: true,
hide: !canAddNormal,
imgConfig: {
commonImageList: {
title: '公共滑动图',
......@@ -37,7 +37,7 @@ export const TaskList = [
name: '虚拟商品',
type: 2,
desc: '无需物流',
hide: true,
hide: !canAddNormal,
imgConfig: {
commonImageList: {
title: '公共滑动图',
......@@ -90,6 +90,7 @@ export const TaskList = [
name: '电子卡卷',
type: 4,
desc: '无需物流',
hide: !canAddService,
imgConfig: {
commonImageList: {
title: '封面图片',
......
......@@ -8,6 +8,7 @@ import FormPriceOrStock from './components/FormPriceOrStock';
import FormRuleSetting from './components/FormRuleSetting';
import FormRuleVPictures from './components/FormRuleVPictures';
import FormSettlementOthers from './components/FormSettlementOthers';
import FormAttr from './components/FormAttr';
import {
merchantBrandList,
merchantSpecList,
......@@ -21,6 +22,7 @@ import {
} from './service';
import { isUrl, filterSendData, clearCurrent } from './utils';
import { ServiceContext } from './context';
import { GOOD_MANAGE } from '@/../config/permission.config';
/**
* 服务商品改造-商品模块
......@@ -28,17 +30,21 @@ import { ServiceContext } from './context';
* @returns ReactDOM
*/
const ServiceGoods = options => {
const { SourceData, categoryList, virtualCategoryList, specListData } = options;
const { SourceData, categoryList, virtualCategoryList, specListData, permissions } = options;
const canAddService = permissions[GOOD_MANAGE.ADD_SERVICE_GOODS];
const canAddNormal = permissions[GOOD_MANAGE.ADD_NORMAL_GOODS];
const basicRef = useRef(null);
const stockRef = useRef(null);
const settingRef = useRef(null);
const picturesRef = useRef(null);
const settleOtrRef = useRef(null);
const attrRef = useRef(null);
const [pageId, setPageId] = useState(null);
const [categoryIds, setCategoryIds] = useState([]); // 商品品类ID
const [isEdit, setIsEdit] = useState(false); // 是否是编辑状态
const [productType, setProductType] = useState(4); // 商品状态
const [productType, setProductType] = useState(1); // 商品状态 canAddNormal ? 1 : 4
const [pageLoading, setPageLoading] = useState(false); // 页面加载状态
const [afterAddressList, setAfterAddressList] = useState([]); // 售后地址
const [supplierIdList, setSupplierIdList] = useState([]); // 适用们店列表
......@@ -48,7 +54,14 @@ const ServiceGoods = options => {
const [editData, setEditData] = useState({}); // 编辑保存数据
const [newCategoryList, setNewCategoryList] = useState({});
// const [shopList, setShopList] = useState([]); // 供应商列表
const [checkFormList] = useState([basicRef, stockRef, settingRef, settleOtrRef, picturesRef]);
const [checkFormList] = useState([
basicRef,
attrRef,
stockRef,
settingRef,
settleOtrRef,
picturesRef,
]);
const [specKeyList, setSpecKeyList] = useState([]); // 记录一级规格key字段
......@@ -186,9 +199,12 @@ const ServiceGoods = options => {
setEditData(SourceData);
setPageId(SourceData.id);
setProductType(SourceData.productType);
setCategoryIds(SourceData.infoMation.categoryId || []);
// changeCheckList(SourceData.productType);
setIsEdit(true);
}
console.log('111 :>> ', 111);
setPageLoading(false);
})();
}, [SourceData]);
......@@ -225,11 +241,16 @@ const ServiceGoods = options => {
});
}
};
const onCategoryChange = e => {
setCategoryIds(e);
};
const providerValue = {
pageId,
isEdit,
productType,
canAddService, // 是否可以添加服务商品(电子卡券)
canAddNormal, // 是否可以添加实物商品
isCard: productType === 4,
isService: SourceData.state && SourceData.state !== 4,
isJDGoods: isEdit && SourceData.pageProductType && +SourceData.pageProductType !== 1,
......@@ -270,8 +291,14 @@ const ServiceGoods = options => {
brandList={brandList}
afterAddressList={afterAddressList}
specListData={specListData}
onCategoryChange={onCategoryChange}
/>
{[1, 2].includes(productType) && [
<Title title="商品属性" />,
<FormAttr ref={attrRef} categoryIds={categoryIds} initData={editData} />,
]}
<Title title="价格与库存" />
<FormPriceOrStock
ref={stockRef}
......
......@@ -97,3 +97,9 @@ export const getByProductType = type =>
prefix: goodsApi,
headers,
});
// 获取类目关联属性
export const apiGetAttribute = categoryId =>
request.get(`/api/kdsp/category/template/ref/attribute/detail?categoryId=${categoryId}`, {
prefix: goodsApi,
});
......@@ -94,7 +94,9 @@ class Socket extends EventEmitter {
}
}, 5000);
};
reconnect();
if (process.env.NODE_ENV === 'production') {
reconnect();
}
};
onerror = e => {
......@@ -126,9 +128,9 @@ class Socket extends EventEmitter {
// 保持连接-默认每3分钟重置一下服务器关闭时间
heartBeat(time) {
console.log('ws: call heartBeat', new Date().getTime());
// console.log('ws: call heartBeat', new Date().getTime());
this.heartBeatTimer = setTimeout(() => {
console.log('ws: sent heart beat', new Date().getTime());
// console.log('ws: sent heart beat', new Date().getTime());
this.sendMessage('HeartBeat');
this.heartBeat(time);
}, time || 45000);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment