Sfoglia il codice sorgente

update:sample editor css style

dev
powersir 1 anno fa
parent
commit
4b75157a3d
5 ha cambiato i file con 142 aggiunte e 113 eliminazioni
  1. +100
    -94
      src/pages/custom/product/sample/components/attr-editor.tsx
  2. +20
    -6
      src/pages/custom/product/sample/components/editor.css
  3. +13
    -4
      src/pages/custom/product/sample/editor/index.css
  4. +9
    -8
      src/pages/custom/product/sample/editor/index.tsx
  5. +0
    -1
      src/pages/custom/product/sample/index.tsx

+ 100
- 94
src/pages/custom/product/sample/components/attr-editor.tsx Vedi File

@@ -1,18 +1,18 @@
import React, { useEffect, useMemo, useState } from 'react'
import { CloseOutlined, DeleteOutlined, PlusOutlined } from '@ant-design/icons';
import { Drawer, Form, Input, Card, Space, Button, Upload, Popconfirm, Modal, FormListOperation, FormListFieldData } from 'antd'
import { Drawer, Form, Input, Card, Space, Button, Upload, Popconfirm, Modal, FormListOperation, FormListFieldData, Tooltip } from 'antd'
import type { RcFile, UploadProps } from 'antd/es/upload';
import type { UploadFile } from 'antd/es/upload/interface';
import './editor.css';

const layout = {
labelCol: { span: 4, },
wrapperCol: { span: 16 },
labelCol: { span: 5, },
wrapperCol: { span: 15 },
};

interface AttributeValue {
id: number;
attrId: number;
id?: number;
attrId?: number;
valName: string;
imgId?: number;
imgUrl?: string;
@@ -29,7 +29,6 @@ export interface SampleAttribute {
interface CreateSampleAttrProps {
visible: boolean;
onCancel: (flag?: boolean) => void;
curRecord?: SampleAttribute[] | null;
onSave: () => void;
editData?: SampleAttribute[] | null;
}
@@ -45,7 +44,7 @@ const getBase64 = (file: RcFile): Promise<string> =>

const SampleAttrEditor: React.FC<CreateSampleAttrProps> = (props) => {

const { visible, onCancel, curRecord, onSave, editData } = props;
const { visible, onCancel, onSave, editData } = props;
const [saveLoading, setSaveLoading] = useState(false);
const [previewOpen, setPreviewOpen] = useState(false);
const [previewImage, setPreviewImage] = useState('');
@@ -61,6 +60,9 @@ const SampleAttrEditor: React.FC<CreateSampleAttrProps> = (props) => {
}, [visible]);

async function setInitValue() {
if (editData) {
form.setFieldsValue({ attrData: editData });
}
}

const save = async (values: any) => {
@@ -92,64 +94,59 @@ const SampleAttrEditor: React.FC<CreateSampleAttrProps> = (props) => {
// setFileList(newFileList);
}

// const [fileList, setFileList] = useState<UploadFile[]>([
// {
// uid: '-1',
// name: 'image.png',
// status: 'done',
// url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
// },
// ]);


const readerAttrValueEditForm = (subFields: FormListFieldData[], attrVals: AttributeValue[], { remove, add }: FormListOperation, isContainImg: boolean) => {
return (<div style={{ display: 'flex', flexDirection: 'column', rowGap: 16 }}>
{subFields.map((subField) => {
const item = attrVals[subField.key];
const uploadFile: UploadFile | null = item.imgUrl && item.imgId ? {
uid: `${item.imgId}`,
name: '',
status: 'done',
url: item.imgUrl
} : null
const fileList: UploadFile[] = [];
if(uploadFile) {
fileList.push(uploadFile)
}
return (
<Space key={subField.key}>
<Form.Item noStyle name={[subField.name, 'valName']}>
<Input size='middle' />
</Form.Item>
{isContainImg && <Form.Item noStyle shouldUpdate name={[subField.name, 'imgUrl']}>
<Upload
action="https://run.mocky.io/v3/435e224c-44fb-4773-9faf-380c5e6a2188"
listType="picture-card"
onPreview={handlePreview}
onChange={handleChange}
maxCount={1}
defaultFileList={[...fileList]}
>
{fileList.length > 0 ? null : uploadButton}
</Upload>
return (
<div style={{ display: 'flex', flexDirection: 'column', rowGap: 16 }}>
{subFields.map((subField) => {
const item = attrVals[subField.key];
const uploadFile: UploadFile | null = item && item.imgUrl && item.imgId ? {
uid: `${item.imgId}`,
name: '',
status: 'done',
url: item.imgUrl
} : null
const fileList: UploadFile[] = [];
if (uploadFile) {
fileList.push(uploadFile)
}
return (
<Form.Item {...subField} style={{marginBottom: 0}}>
<Space key={subField.key}>
<Form.Item noStyle name={[subField.name, 'valName']}>
<Input size='middle' />
</Form.Item>
{isContainImg && <Form.Item noStyle shouldUpdate name={[subField.name, 'imgUrl']}>
<Upload className='attr-image'
action="https://run.mocky.io/v3/435e224c-44fb-4773-9faf-380c5e6a2188"
listType="picture-card"
onPreview={handlePreview}
onChange={handleChange}
maxCount={1}
defaultFileList={[...fileList]}
>
{fileList.length > 0 ? null : uploadButton}
</Upload>
</Form.Item>
}
<Popconfirm
title="删除属性值"
description="确认是否删除当前属性值?"
onConfirm={() => { remove(subField.name); }}
okText="确认"
cancelText="取消"
>
<Tooltip title="删除属性值">
<DeleteOutlined className='delete-icon'/>
</Tooltip>
</Popconfirm>
</Space>
</Form.Item>
}
<Popconfirm
title="删除属性值"
description="确认是否删除当前属性值?"
onConfirm={() => { remove(subField.name); }}
okText="确认"
cancelText="取消"
>
<DeleteOutlined />
</Popconfirm>
</Space>
)
})}
<Button type="dashed" size='middle' onClick={() => add()} block>
+ 添加自定义值
</Button>
</div>)
)
})}
<Button type="dashed" size='middle' onClick={() => add({ valName: '', imgUrl: '', imgId: 0 })} block>
+ 添加自定义值
</Button>
</div>)
}

const renderAttrEditForm = (fields: FormListFieldData[], { remove, add }: FormListOperation, dataSource: SampleAttribute[]) => {
@@ -158,35 +155,47 @@ const SampleAttrEditor: React.FC<CreateSampleAttrProps> = (props) => {
{fields.map((field) => {
const data = dataSource[field.key];
return (
<Card size="small" title={field.name} key={field.key}
extra={
<Popconfirm
title="删除属性"
description="确认是否删除当前属性?"
onConfirm={() => { remove(field.name); }}
okText="确认"
cancelText="取消"
>
<CloseOutlined style={{ fontSize: '16px' }} className='hover:(bg-[rgb(94,53,177)]' />
</Popconfirm>
}
>
<Form.Item label="属性名称" name={[field.name, 'attrName']}>
<Input size='middle' />
</Form.Item>

<Form.Item label="属性值">
<Form.List name={[field.name, 'attrVals']}>
{(subFields, subOpt) => {
return readerAttrValueEditForm(subFields, data.attrVals, subOpt, data.isContainImg === 1)
}}
</Form.List>
</Form.Item>
</Card>
<Form.Item {...field} style={{marginBottom: 4}}>
<Card size="small" title={field.name} key={field.key}
style={{ width: 500 }}
extra={
<Popconfirm
title="删除属性"
description="确认是否删除当前属性?"
onConfirm={() => { remove(field.name); }}
okText="确认"
cancelText="取消"
>
<Tooltip title="删除属性">
<CloseOutlined style={{ fontSize: '16px' }} className='delete-icon' />
</Tooltip>
</Popconfirm>
}
>
<Form.Item label="属性名称" name={[field.name, 'attrName']} labelCol={{ span: 4 }}>
<Input size='middle' />
</Form.Item>

<Form.Item label="属性值" labelCol={{ span: 4 }}>
<Form.List name={[field.name, 'attrVals']}>
{(subFields, subOpt) => {
return readerAttrValueEditForm(subFields, data.attrVals, subOpt, data.isContainImg === 1)
}}
</Form.List>
</Form.Item>
</Card>
</Form.Item>

)
})}

<Button type="dashed" size='middle' onClick={() => add()} block>
<Button type="dashed" size='middle' onClick={() => add({
"prototypeId": 88,
"attrName": "",
"isContainImg": 1,
"attrVals": [
]
},)} block>
+ 添加属性
</Button>
</div>
@@ -212,15 +221,12 @@ const SampleAttrEditor: React.FC<CreateSampleAttrProps> = (props) => {
<Form
form={form}
{...layout}
initialValues={{ editData }}
onFinish={save}
labelCol={{ flex: '0 0 100px' }}
wrapperCol={{ span: 16 }}
>
<Form.List name="editData">
{(fields, operation) => {
return renderAttrEditForm(fields, operation, editData!!)
}}
<Form.List name="attrData">
{(fields, operation) => renderAttrEditForm(fields, operation, form.getFieldsValue()['attrData'])}
</Form.List>

</Form>


+ 20
- 6
src/pages/custom/product/sample/components/editor.css Vedi File

@@ -1,5 +1,10 @@
:where(.css-dev-only-do-not-override-11asvft).ant-upload-wrapper.ant-upload-picture-card-wrapper .ant-upload.ant-upload-select, :where(.css-dev-only-do-not-override-11asvft).ant-upload-wrapper.ant-upload-picture-circle-wrapper .ant-upload.ant-upload-select {
height: 40px;
.attr-image {
height: 50px;
}

:where(.attr-image).ant-upload-wrapper.ant-upload-picture-card-wrapper .ant-upload.ant-upload-select,
:where(.attr-image).ant-upload-wrapper.ant-upload-picture-circle-wrapper .ant-upload.ant-upload-select {
height: 50px;
margin-inline-end: 8px;
margin-bottom: 0;
text-align: center;
@@ -12,10 +17,13 @@
}


:where(.css-dev-only-do-not-override-11asvft).ant-upload-wrapper.ant-upload-picture-card-wrapper .ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item-container, :where(.css-dev-only-do-not-override-11asvft).ant-upload-wrapper.ant-upload-picture-circle-wrapper .ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item-container, :where(.css-dev-only-do-not-override-11asvft).ant-upload-wrapper.ant-upload-picture-card-wrapper .ant-upload-list.ant-upload-list-picture-circle .ant-upload-list-item-container, :where(.css-dev-only-do-not-override-11asvft).ant-upload-wrapper.ant-upload-picture-circle-wrapper .ant-upload-list.ant-upload-list-picture-circle .ant-upload-list-item-container {
:where(.attr-image).ant-upload-wrapper.ant-upload-picture-card-wrapper .ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item-container,
:where(.attr-image).ant-upload-wrapper.ant-upload-picture-circle-wrapper .ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item-container,
:where(.attr-image).ant-upload-wrapper.ant-upload-picture-card-wrapper .ant-upload-list.ant-upload-list-picture-circle .ant-upload-list-item-container,
:where(.attr-image).ant-upload-wrapper.ant-upload-picture-circle-wrapper .ant-upload-list.ant-upload-list-picture-circle .ant-upload-list-item-container {
display: inline-block;
width: 40px;
height: 40px;
width: 50px;
height: 50px;
margin-block: 0 8px;
margin-inline: 0 8px;
margin: 0 2px;
@@ -23,9 +31,15 @@
}


:where(.css-dev-only-do-not-override-11asvft).ant-upload-wrapper .ant-upload-list.ant-upload-list-picture .ant-upload-list-item, :where(.css-dev-only-do-not-override-11asvft).ant-upload-wrapper .ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item, :where(.css-dev-only-do-not-override-11asvft).ant-upload-wrapper .ant-upload-list.ant-upload-list-picture-circle .ant-upload-list-item {
:where(.attr-image).ant-upload-wrapper .ant-upload-list.ant-upload-list-picture .ant-upload-list-item,
:where(.attr-image).ant-upload-wrapper .ant-upload-list.ant-upload-list-picture-card .ant-upload-list-item,
:where(.attr-image).ant-upload-wrapper .ant-upload-list.ant-upload-list-picture-circle .ant-upload-list-item {
position: relative;
padding: 1px;
border: 1px solid #d9d9d9;
border-radius: 2px;
}

.delete-icon:hover {
color: #646cffaa;
}

+ 13
- 4
src/pages/custom/product/sample/editor/index.css Vedi File

@@ -1,17 +1,26 @@
:where(.css-dev-only-do-not-override-11asvft).ant-card .ant-card-body {
.workbench {}

:where(.workbench).ant-card .ant-card-body {
padding: 0;
border-radius: 0 0 8px 8px;
}

:where(.css-dev-only-do-not-override-phnixs).ant-card .ant-card-body {
:where(.workbench).ant-card .ant-card-body {
padding: 0;
border-radius: 0 0 8px 8px;
}

:where(.css-dev-only-do-not-override-phnixs).ant-list-lg .ant-list-item {
:where(.workbench).ant-list-lg .ant-list-item {
padding: 16px 8px;
}

:where(.css-dev-only-do-not-override-11asvft).ant-list-lg .ant-list-item {
:where(.workbench).ant-list-lg .ant-list-item {
padding: 16px 8px;
}


:where(.workbench).ant-list .ant-spin-container {
position: relative;
transition: opacity 0.3s;
margin-top: 10px;
}

+ 9
- 8
src/pages/custom/product/sample/editor/index.tsx Vedi File

@@ -7,7 +7,7 @@ import 'react-advanced-cropper/dist/style.css';
import { ImageStencil } from "./components/ImageStencil";
import { DeleteOutlined, EditOutlined, UploadOutlined } from '@ant-design/icons';
import cn from 'classnames';
import './index.css'
import './index.css';
import property from '../../../../../../mock/propertyById.json'

interface SampleProperty {
@@ -113,8 +113,8 @@ export default () => {

return (
<div className='flex'>
<Card className='flex-none mb-[10px] w-[270px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]'>
<div style={{ padding: '20px' }}>
<Card className='flex-none mb-[10px] w-[270px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px] workbench'>
<div style={{ padding: '20px 20px 0 20px' }}>
<Anchor
direction="horizontal"
items={[
@@ -133,21 +133,21 @@ export default () => {
</div>
<div >
<div >
<div id="part-1" >
<div id="part-1">
<List dataSource={sample.prototypeImgs.filter(it => it.imgType === 2)}
grid={{
gutter: 2,
column: 2
}}
header={(
<div className='flex justify-center'>
<div className='flex justify-center' >
<Upload {...props}>
<Button icon={<UploadOutlined />}>点击上传主图</Button>
</Upload>
</div>
)}
renderItem={(item) => (renderListItem(item))}
className='workbench'
/>
</div>
<div id="part-2">
@@ -165,13 +165,14 @@ export default () => {
</div>
)}
renderItem={(item) => (renderListItem(item))}
className='workbench'
/>
</div>
</div>
</div>
</Card>

<Card className='flex-auto mx-[10px] mb-[10px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]'>
<Card className='flex-auto mx-[10px] mb-[10px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px] workbench'>
<div className='flex flex-col justify-center'>
<div className='flex justify-center text-3xl p-5 font-extrabold'>工作台</div>
<div className='flex justify-center'>
@@ -201,7 +202,7 @@ export default () => {
</div>
</Card>

<Card className='flex-none mb-[10px] w-[270px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]'>
<Card className='flex-none mb-[10px] w-[270px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px] workbench'>
<div className='flex justify-center pt-2'>
<Radio.Group options={options}
onChange={onStyleChanged}


+ 0
- 1
src/pages/custom/product/sample/index.tsx Vedi File

@@ -384,7 +384,6 @@ const TablePage: React.FC = () => {
onSave={saveAttributeHandle}
onCancel={cancelHandle}
visible={attrEditorVisible}
curRecord={attrData}
editData={attrData} />

<MaskPictureEditor


Loading…
Annulla
Salva