|
@@ -0,0 +1,250 @@
|
|
|
|
|
+import { App, Button, Dropdown, Form, Input, message, Modal, Radio, Select } from "antd"
|
|
|
|
|
+import React, { useEffect, useState } from "react"
|
|
|
|
|
+import UploadImg from "../../components/materialMould/uploadImg"
|
|
|
|
|
+import UploadVideo from "../../components/materialMould/uploadVideo"
|
|
|
|
|
+import { CloseCircleOutlined, MinusOutlined, PlusOutlined } from '@ant-design/icons';
|
|
|
|
|
+import { useAjax } from "@/Hook/useAjax";
|
|
|
|
|
+import { createLandingPageApi, editLandingPageApi } from "../../API/miniProgramPages";
|
|
|
|
|
+
|
|
|
|
|
+interface Props {
|
|
|
|
|
+ groupList: { label: string, value: number }[]
|
|
|
|
|
+ visible?: boolean
|
|
|
|
|
+ onChange?: () => void
|
|
|
|
|
+ onClose?: () => void
|
|
|
|
|
+ initialValues?: any
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const NewMini: React.FC<Props> = ({ visible, onChange, onClose, groupList, initialValues }) => {
|
|
|
|
|
+
|
|
|
|
|
+ /***********************************/
|
|
|
|
|
+ const { message } = App.useApp();
|
|
|
|
|
+ const [form] = Form.useForm();
|
|
|
|
|
+ const elementType = Form.useWatch(['topSpec', 'elementType'], form)
|
|
|
|
|
+ const elementsSpecList = Form.useWatch(['pageSpecsList', 'elementsSpecList'], form)
|
|
|
|
|
+
|
|
|
|
|
+ const createLandingPage = useAjax((params) => createLandingPageApi(params))
|
|
|
|
|
+ const editLandingPage = useAjax((params) => editLandingPageApi(params))
|
|
|
|
|
+ /***********************************/
|
|
|
|
|
+
|
|
|
|
|
+ const handleOk = () => {
|
|
|
|
|
+ form.validateFields().then(valid => {
|
|
|
|
|
+ const siteId = Date.now()
|
|
|
|
|
+ const { pageSpecsList, floatButtonSpec, topSpec, qrCodeFloatList, ...v } = valid
|
|
|
|
|
+ floatButtonSpec.elementType = 'FLOAT_BUTTON'
|
|
|
|
|
+ floatButtonSpec.id = siteId
|
|
|
|
|
+ pageSpecsList.elementsSpecList.unshift(topSpec)
|
|
|
|
|
+ pageSpecsList.elementsSpecList.push(floatButtonSpec)
|
|
|
|
|
+ const qrCodeList = pageSpecsList.elementsSpecList.filter(item => item.elementType === 'QR_CODE')?.map(item => ({ siteId: item.id, urlList: item.imageList }))
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ content: JSON.stringify(pageSpecsList),
|
|
|
|
|
+ qrCodeFloatList: [{
|
|
|
|
|
+ siteId,
|
|
|
|
|
+ urlList: qrCodeFloatList
|
|
|
|
|
+ }],
|
|
|
|
|
+ qrCodeList,
|
|
|
|
|
+ ...v
|
|
|
|
|
+ }
|
|
|
|
|
+ if (initialValues?.id) {
|
|
|
|
|
+ editLandingPage.run({ ...params, id: initialValues.id }).then(res => {
|
|
|
|
|
+ if (res?.data) {
|
|
|
|
|
+ message.success('修改成功')
|
|
|
|
|
+ onChange?.()
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ } else {
|
|
|
|
|
+ createLandingPage.run(params).then(res => {
|
|
|
|
|
+ if (res?.data) {
|
|
|
|
|
+ message.success('新增成功')
|
|
|
|
|
+ onChange?.()
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ }).catch(err => { })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return <Modal
|
|
|
|
|
+ title={<strong>{initialValues?.id ? initialValues?.isCopy ? '复制落地页' : '修改' + initialValues.name + '落地页' : '新增落地页'}</strong>}
|
|
|
|
|
+ open={visible}
|
|
|
|
|
+ onCancel={onClose}
|
|
|
|
|
+ onOk={handleOk}
|
|
|
|
|
+ width={750}
|
|
|
|
|
+ confirmLoading={createLandingPage?.loading || editLandingPage?.loading}
|
|
|
|
|
+ maskClosable={false}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Form
|
|
|
|
|
+ form={form}
|
|
|
|
|
+ name="newPageLink"
|
|
|
|
|
+ labelAlign='left'
|
|
|
|
|
+ labelCol={{ span: 5 }}
|
|
|
|
|
+ colon={false}
|
|
|
|
|
+ scrollToFirstError={{
|
|
|
|
|
+ behavior: 'smooth',
|
|
|
|
|
+ block: 'center'
|
|
|
|
|
+ }}
|
|
|
|
|
+ onFinishFailed={({ errorFields }) => {
|
|
|
|
|
+ message.error(errorFields?.[0]?.errors?.[0])
|
|
|
|
|
+ }}
|
|
|
|
|
+ onFinish={handleOk}
|
|
|
|
|
+ initialValues={initialValues || {
|
|
|
|
|
+ topSpec: {
|
|
|
|
|
+ elementType: 'TOP_IMAGE',
|
|
|
|
|
+ },
|
|
|
|
|
+ pageSpecsList: {
|
|
|
|
|
+ elementsSpecList: [{ elementType: 'TEXT' }],
|
|
|
|
|
+ bgColor: '#EAEAEF'
|
|
|
|
|
+ },
|
|
|
|
|
+ floatButtonSpec: {
|
|
|
|
|
+ elementType: 'FLOAT_BUTTON',
|
|
|
|
|
+ title: '长按添加客服看下一章'
|
|
|
|
|
+ },
|
|
|
|
|
+ qrCodeFloatList: ['']
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Form.Item label={<strong>落地页名称</strong>} name="name" rules={[{ required: true, message: '请输入落地页名称!' }]}>
|
|
|
|
|
+ <Input placeholder="请输入落地页名称" />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ <Form.Item label={<strong>落地页备注</strong>} name="remark">
|
|
|
|
|
+ <Input placeholder="请输入落地页备注" />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ <Form.Item label={<strong>项目组</strong>} name="projectGroupIdList" rules={[{ required: true, message: '请选择项目组!' }]}>
|
|
|
|
|
+ <Select
|
|
|
|
|
+ placeholder='请选择项目组'
|
|
|
|
|
+ allowClear
|
|
|
|
|
+ options={groupList}
|
|
|
|
|
+ showSearch
|
|
|
|
|
+ mode="multiple"
|
|
|
|
|
+ filterOption={(input, option) =>
|
|
|
|
|
+ (option?.label ?? '').toLowerCase().includes(input.toLowerCase())
|
|
|
|
|
+ }
|
|
|
|
|
+ />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ <Form.Item label={<strong>顶部素材</strong>} required>
|
|
|
|
|
+ <Form.Item name={['topSpec', 'elementType']} rules={[{ required: true, message: '请选择顶部素材类型!' }]}>
|
|
|
|
|
+ <Radio.Group
|
|
|
|
|
+ options={[
|
|
|
|
|
+ { value: 'TOP_IMAGE', label: '图片' },
|
|
|
|
|
+ { value: 'TOP_VIDEO', label: '视频' }
|
|
|
|
|
+ ]}
|
|
|
|
|
+ />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ {elementType === 'TOP_IMAGE' ? <Form.Item name={['topSpec', 'url']} rules={[{ required: true, message: '请上传图片!' }]}>
|
|
|
|
|
+ <UploadImg isCropper />
|
|
|
|
|
+ </Form.Item> : <Form.Item name={['topSpec', 'url']} rules={[{ required: true, message: '请上传视频!' }]}>
|
|
|
|
|
+ <UploadVideo />
|
|
|
|
|
+ </Form.Item>}
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ <Form.List name={['pageSpecsList', 'elementsSpecList']} >
|
|
|
|
|
+ {(fields, { add, remove }) => {
|
|
|
|
|
+ return <>
|
|
|
|
|
+ {fields.map(({ key, name, ...restField }, index) => {
|
|
|
|
|
+ const elementsSpec = elementsSpecList?.[index]
|
|
|
|
|
+ const imageList = elementsSpec?.imageList
|
|
|
|
|
+ return <div key={index} style={{ backgroundColor: 'rgba(0,0,0,0.05)', padding: 10, borderRadius: 8, marginBottom: 10 }}>
|
|
|
|
|
+ <h3 style={{ display: 'flex', justifyContent: 'space-between', margin: 0, paddingLeft: 10, marginBottom: 5 }}>
|
|
|
|
|
+ <span>{elementsSpec?.elementType === 'QR_CODE' && '客服号二维码图片'}</span>
|
|
|
|
|
+ {fields?.length > 1 && <Button
|
|
|
|
|
+ type="dashed"
|
|
|
|
|
+ danger
|
|
|
|
|
+ onClick={() => remove(index)}
|
|
|
|
|
+ icon={<MinusOutlined />}
|
|
|
|
|
+ size='small'
|
|
|
|
|
+ >
|
|
|
|
|
+ 移除内容
|
|
|
|
|
+ </Button>}
|
|
|
|
|
+ </h3>
|
|
|
|
|
+ {elementsSpec?.elementType === 'TEXT' ? <Form.Item
|
|
|
|
|
+ {...restField}
|
|
|
|
|
+ label={<strong>文本内容</strong>}
|
|
|
|
|
+ name={[name, 'text']}
|
|
|
|
|
+ rules={[{ required: true, message: '请输入文本内容!' }]}
|
|
|
|
|
+ >
|
|
|
|
|
+ <Input.TextArea placeholder="请输入文案内容" rows={4} />
|
|
|
|
|
+ </Form.Item> : elementsSpec?.elementType === 'QR_CODE' ? <>
|
|
|
|
|
+ <Form.List name={[name, 'imageList']}>
|
|
|
|
|
+ {(fields, { add, remove }) => {
|
|
|
|
|
+ return <div style={{ display: 'flex', flexWrap: 'wrap', padding: '0 5px' }}>
|
|
|
|
|
+ {fields.map(({ key, name, ...restField }, index) => {
|
|
|
|
|
+ return <div key={index} style={{ position: 'relative', margin: '5px 5px 0 5px' }}>
|
|
|
|
|
+ <Form.Item
|
|
|
|
|
+ {...restField}
|
|
|
|
|
+ name={[name]}
|
|
|
|
|
+ rules={[{ required: true, message: '请上传企微客服二维码!' }]}
|
|
|
|
|
+ >
|
|
|
|
|
+ <UploadImg isCropper />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ {imageList?.length > 1 && <div style={{ position: 'absolute', top: -10, right: -10 }}><Button icon={<CloseCircleOutlined />} danger onClick={() => remove(index)} type="text" size="small" /></div>}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ })}
|
|
|
|
|
+ <Form.Item noStyle>
|
|
|
|
|
+ <Button type="primary" disabled onClick={() => add()} style={{ width: '100%' }} icon={<PlusOutlined />}>
|
|
|
|
|
+ 新增客服二维码图片
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ }}
|
|
|
|
|
+ </Form.List>
|
|
|
|
|
+ </> : elementsSpec?.elementType === 'IMAGE' ? <>
|
|
|
|
|
+ <Form.Item
|
|
|
|
|
+ {...restField}
|
|
|
|
|
+ label={<strong>图片内容</strong>}
|
|
|
|
|
+ name={[name, 'url']}
|
|
|
|
|
+ rules={[{ required: true, message: '请上传图片!' }]}
|
|
|
|
|
+ >
|
|
|
|
|
+ <UploadImg isCropper />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </> : null}
|
|
|
|
|
+
|
|
|
|
|
+ </div>
|
|
|
|
|
+ })}
|
|
|
|
|
+ <Form.Item noStyle>
|
|
|
|
|
+ <Dropdown
|
|
|
|
|
+ menu={{
|
|
|
|
|
+ items: [
|
|
|
|
|
+ { key: '1', label: '文本', onClick: () => add({ elementType: 'TEXT' }) },
|
|
|
|
|
+ { key: '2', label: '图片', onClick: () => add({ elementType: 'IMAGE' }) },
|
|
|
|
|
+ { key: '3', label: '客服号二维码', onClick: () => add({ elementType: 'QR_CODE', id: Date.now(), imageList: [''] }) },
|
|
|
|
|
+ ]
|
|
|
|
|
+ }}
|
|
|
|
|
+ placement="topLeft"
|
|
|
|
|
+ >
|
|
|
|
|
+ <Button type="dashed" style={{ width: '100%', marginBottom: 20 }} icon={<PlusOutlined />}>
|
|
|
|
|
+ 新增组件
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ </Dropdown>
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </>
|
|
|
|
|
+ }}
|
|
|
|
|
+ </Form.List>
|
|
|
|
|
+ <Form.Item label={<strong>底部悬浮</strong>} required>
|
|
|
|
|
+ <Form.Item name={['floatButtonSpec', 'title']} rules={[{ required: true, message: '请输入悬浮组件标题!' }]}>
|
|
|
|
|
+ <Input placeholder="请输入悬浮组件标题" disabled />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ <Form.List name={['qrCodeFloatList']}>
|
|
|
|
|
+ {(fields, { add, remove }) => {
|
|
|
|
|
+ return <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10 }}>
|
|
|
|
|
+ {fields.map(({ key, name, ...restField }, index) => {
|
|
|
|
|
+ return <div key={index} style={{ position: 'relative' }}>
|
|
|
|
|
+ <Form.Item
|
|
|
|
|
+ {...restField}
|
|
|
|
|
+ name={[name]}
|
|
|
|
|
+ rules={[{ required: true, message: '请上传企微客服二维码!' }]}
|
|
|
|
|
+ >
|
|
|
|
|
+ <UploadImg isCropper />
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ {/* <div style={{ position: 'absolute', top: -10, right: -10 }}><Button icon={<CloseCircleOutlined />} danger onClick={() => remove(index)} type="text" size="small" /></div> */}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ })}
|
|
|
|
|
+ {/* <Form.Item noStyle>
|
|
|
|
|
+ <Button type="dashed" onClick={() => add()} style={{ width: '100%' }} icon={<PlusOutlined />}>
|
|
|
|
|
+ 新增客服二维码
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ </Form.Item> */}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ }}
|
|
|
|
|
+ </Form.List>
|
|
|
|
|
+ </Form.Item>
|
|
|
|
|
+ </Form>
|
|
|
|
|
+ </Modal>
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export default React.memo(NewMini)
|