|
@@ -0,0 +1,372 @@
|
|
|
|
+import { IconImage } from "@/assets/icons";
|
|
|
|
+import { useEditor } from "@/modules/editor";
|
|
|
|
+import { SelectOneImage } from "@/pages/website/Material2/modal";
|
|
|
|
+import { PlusOutlined } from "@ant-design/icons-vue";
|
|
|
|
+import { css } from "@linaria/core";
|
|
|
|
+import { IconAddLine } from "@queenjs/icons";
|
|
|
|
+import { Image } from "@queenjs/ui";
|
|
|
|
+import {
|
|
|
|
+ Button,
|
|
|
|
+ DatePicker,
|
|
|
|
+ Divider,
|
|
|
|
+ Form,
|
|
|
|
+ Input,
|
|
|
|
+ Select,
|
|
|
|
+} from "ant-design-vue";
|
|
|
|
+import locale from "ant-design-vue/es/date-picker/locale/zh_CN";
|
|
|
|
+import dayjs, { Dayjs } from "dayjs";
|
|
|
|
+import localeData from "dayjs/plugin/localeData";
|
|
|
|
+import weekday from "dayjs/plugin/weekday";
|
|
|
|
+import { queenApi, useModal } from "queenjs";
|
|
|
|
+import { defineComponent, reactive } from "vue";
|
|
|
|
+import { any, string } from "vue-types";
|
|
|
|
+import { useResource } from "..";
|
|
|
|
+
|
|
|
|
+const layout = {
|
|
|
|
+ labelCol: { span: 8 },
|
|
|
|
+ wrapperCol: { span: 16 },
|
|
|
|
+};
|
|
|
|
+dayjs.extend(weekday);
|
|
|
|
+dayjs.extend(localeData);
|
|
|
|
+const { RangePicker } = DatePicker;
|
|
|
|
+type RangeValue = [Dayjs, Dayjs];
|
|
|
|
+export default defineComponent({
|
|
|
|
+ props: {
|
|
|
|
+ record: any().isRequired,
|
|
|
|
+ },
|
|
|
|
+ setup(props, { slots }) {
|
|
|
|
+ const dateLocal: any = locale;
|
|
|
|
+ dateLocal.lang.shortWeekDays = "日_一_二_三_四_五_六".split("_");
|
|
|
|
+ dateLocal.lang.shortMonths =
|
|
|
|
+ "1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_");
|
|
|
|
+ const modal = useModal();
|
|
|
|
+ const data = props.record
|
|
|
|
+ ? { ...props.record }
|
|
|
|
+ : {
|
|
|
|
+ cover: "",
|
|
|
|
+ logo: "",
|
|
|
|
+ introLink: "",
|
|
|
|
+ introH5Id: "",
|
|
|
|
+ statues: [],
|
|
|
|
+ flags: [],
|
|
|
|
+ status: "",
|
|
|
|
+ title: "",
|
|
|
|
+ startTime: undefined,
|
|
|
|
+ endTime: undefined,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ const resource = useResource();
|
|
|
|
+ resource.controls.promotionListCtrl.loadPage(1);
|
|
|
|
+ const formState: { [name: string]: any } = reactive({
|
|
|
|
+ ...data,
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ const state = reactive({
|
|
|
|
+ linkType: "id",
|
|
|
|
+ });
|
|
|
|
+ if (data.introLink) {
|
|
|
|
+ state.linkType = "link";
|
|
|
|
+ }
|
|
|
|
+ const rules = reactive({
|
|
|
|
+ title: [
|
|
|
|
+ { required: true, message: "标题不能为空", trigger: "change" },
|
|
|
|
+ {
|
|
|
|
+ min: 2,
|
|
|
|
+ max: 20,
|
|
|
|
+ message: "长度为2~20位字符",
|
|
|
|
+ trigger: "change",
|
|
|
|
+ },
|
|
|
|
+ ],
|
|
|
|
+ cover: [{ required: true, message: "封面图不能为空", trigger: "change" }],
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ const { validate, validateInfos } = Form.useForm(formState, rules);
|
|
|
|
+
|
|
|
|
+ function submit() {
|
|
|
|
+ validate().then(async () => {
|
|
|
|
+ modal.submit(formState);
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ const pickerRanges = () => {
|
|
|
|
+ return {
|
|
|
|
+ 今天: [dayjs(), dayjs()] as RangeValue,
|
|
|
|
+ 本周: [
|
|
|
|
+ dayjs().startOf("week").add(1, "day"),
|
|
|
|
+ dayjs().endOf("week").add(1, "day"),
|
|
|
|
+ ] as RangeValue,
|
|
|
|
+ 本月: [dayjs().startOf("month"), dayjs().endOf("month")] as RangeValue,
|
|
|
|
+ };
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ const statusOptions = () => {
|
|
|
|
+ const options = formState?.statues?.map((e: any) => {
|
|
|
|
+ return { label: e, value: e };
|
|
|
|
+ });
|
|
|
|
+ return options || [];
|
|
|
|
+ };
|
|
|
|
+ const addStatus = async () => {
|
|
|
|
+ const statues = formState?.statues || [];
|
|
|
|
+ const text = await queenApi.showInput({
|
|
|
|
+ title: "添加状态",
|
|
|
|
+ placeholder: "输入状态名称",
|
|
|
|
+ });
|
|
|
|
+ if (!text) return;
|
|
|
|
+ if (statues.length == 0) {
|
|
|
|
+ formState.status = text;
|
|
|
|
+ }
|
|
|
|
+ statues.push(text);
|
|
|
|
+ formState.statues = statues;
|
|
|
|
+ };
|
|
|
|
+ const flagsOptions = () => {
|
|
|
|
+ const options = formState?.flags?.map((e: any) => {
|
|
|
|
+ return { label: e, value: e };
|
|
|
|
+ });
|
|
|
|
+ return options || [];
|
|
|
|
+ };
|
|
|
|
+ const addFlag = async () => {
|
|
|
|
+ const flags = formState?.flags || [];
|
|
|
|
+ const text = await queenApi.showInput({
|
|
|
|
+ title: "添加标签",
|
|
|
|
+ placeholder: "输入标签名称",
|
|
|
|
+ });
|
|
|
|
+ if (!text) return;
|
|
|
|
+ flags.push(text);
|
|
|
|
+ formState.flags = flags;
|
|
|
|
+ };
|
|
|
|
+ const h5Options = () => {
|
|
|
|
+ const options = resource.controls.promotionListCtrl.state.list.map(
|
|
|
|
+ (e: any) => {
|
|
|
|
+ return { label: e.title, value: e._id };
|
|
|
|
+ }
|
|
|
|
+ );
|
|
|
|
+ return options;
|
|
|
|
+ };
|
|
|
|
+ const scorllEnd = (e: any) => {
|
|
|
|
+ const { target } = e;
|
|
|
|
+ if (target.scrollTop + target.offsetHeight === target.scrollHeight) {
|
|
|
|
+ if (resource.controls.promotionListCtrl.state.canLoadNext) {
|
|
|
|
+ resource.controls.promotionListCtrl.loadNextPage();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+ return () => {
|
|
|
|
+ const time: [Dayjs, Dayjs] | undefined =
|
|
|
|
+ formState.startTime && formState.endTime
|
|
|
|
+ ? [dayjs(formState.startTime), dayjs(formState.endTime)]
|
|
|
|
+ : undefined;
|
|
|
|
+ return (
|
|
|
|
+ <div class={ModalStyle}>
|
|
|
|
+ <Form {...layout} onSubmit={submit}>
|
|
|
|
+ <Form.Item {...validateInfos.cover} wrapperCol={{ span: 24 }}>
|
|
|
|
+ <div class={"w-full h-180px pt-20px"}>
|
|
|
|
+ <ImageUploader
|
|
|
|
+ data={formState.cover}
|
|
|
|
+ text="请选择封面图"
|
|
|
|
+ onChange={(v) => {
|
|
|
|
+ formState.cover = v;
|
|
|
|
+ }}
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+ </Form.Item>
|
|
|
|
+ <Form.Item {...validateInfos.title} label="标题">
|
|
|
|
+ <Input
|
|
|
|
+ placeholder={"请输入标题"}
|
|
|
|
+ v-model={[formState.title, "value"]}
|
|
|
|
+ />
|
|
|
|
+ </Form.Item>
|
|
|
|
+ <Form.Item label="详情介绍">
|
|
|
|
+ <Input.Group compact>
|
|
|
|
+ <Select
|
|
|
|
+ defaultValue={state.linkType}
|
|
|
|
+ onChange={(v: any) => {
|
|
|
|
+ state.linkType = v;
|
|
|
|
+ if (v == "id") {
|
|
|
|
+ formState.introLink = "";
|
|
|
|
+ } else {
|
|
|
|
+ formState.introH5Id = null;
|
|
|
|
+ }
|
|
|
|
+ }}
|
|
|
|
+ >
|
|
|
|
+ <Select.Option value="id">站内作品</Select.Option>
|
|
|
|
+ <Select.Option value="link">站外链接</Select.Option>
|
|
|
|
+ </Select>
|
|
|
|
+ {state.linkType == "link" ? (
|
|
|
|
+ <Input
|
|
|
|
+ class={"flex-1"}
|
|
|
|
+ placeholder={"请输入链接地址"}
|
|
|
|
+ v-model={[formState.introLink, "value"]}
|
|
|
|
+ />
|
|
|
|
+ ) : (
|
|
|
|
+ <Select
|
|
|
|
+ value={formState.introH5Id}
|
|
|
|
+ class={"flex-1"}
|
|
|
|
+ options={h5Options()}
|
|
|
|
+ onPopupScroll={scorllEnd}
|
|
|
|
+ onChange={(v: any) => {
|
|
|
|
+ formState.introH5Id = v;
|
|
|
|
+ }}
|
|
|
|
+ ></Select>
|
|
|
|
+ )}
|
|
|
|
+ </Input.Group>
|
|
|
|
+ </Form.Item>
|
|
|
|
+ <Form.Item label="logo">
|
|
|
|
+ <div class={"w-80px h-80px"}>
|
|
|
|
+ <ImageUploader
|
|
|
|
+ data={formState.logo}
|
|
|
|
+ text="请选择logo"
|
|
|
|
+ icon={<IconAddLine class="text-18px" />}
|
|
|
|
+ onChange={(v) => {
|
|
|
|
+ formState.logo = v;
|
|
|
|
+ }}
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+ </Form.Item>
|
|
|
|
+ <Form.Item label={"自定义状态"}>
|
|
|
|
+ <Select
|
|
|
|
+ options={statusOptions()}
|
|
|
|
+ listHeight={150}
|
|
|
|
+ value={formState.status}
|
|
|
|
+ onChange={(v: any) => {
|
|
|
|
+ formState.status = v;
|
|
|
|
+ }}
|
|
|
|
+ >
|
|
|
|
+ {{
|
|
|
|
+ dropdownRender: ({ menuNode }: any) => {
|
|
|
|
+ return (
|
|
|
|
+ <>
|
|
|
|
+ {menuNode}
|
|
|
|
+ <Divider style={{ margin: 0 }} />
|
|
|
|
+ <Button
|
|
|
|
+ type="link"
|
|
|
|
+ icon={<PlusOutlined />}
|
|
|
|
+ onMousedown={(e) => {
|
|
|
|
+ e.stopPropagation();
|
|
|
|
+ }}
|
|
|
|
+ onClick={addStatus}
|
|
|
|
+ >
|
|
|
|
+ 添加状态
|
|
|
|
+ </Button>
|
|
|
|
+ </>
|
|
|
|
+ );
|
|
|
|
+ },
|
|
|
|
+ }}
|
|
|
|
+ </Select>
|
|
|
|
+ </Form.Item>
|
|
|
|
+ <Form.Item label={"自定义标签"}>
|
|
|
|
+ <Select options={flagsOptions()} listHeight={150}>
|
|
|
|
+ {{
|
|
|
|
+ dropdownRender: ({ menuNode }: any) => {
|
|
|
|
+ return (
|
|
|
|
+ <>
|
|
|
|
+ {menuNode}
|
|
|
|
+ <Divider style={{ margin: 0 }} />
|
|
|
|
+ <Button
|
|
|
|
+ type="link"
|
|
|
|
+ icon={<PlusOutlined />}
|
|
|
|
+ onMousedown={(e) => {
|
|
|
|
+ e.stopPropagation();
|
|
|
|
+ }}
|
|
|
|
+ onClick={addFlag}
|
|
|
|
+ >
|
|
|
|
+ 添加标签
|
|
|
|
+ </Button>
|
|
|
|
+ </>
|
|
|
|
+ );
|
|
|
|
+ },
|
|
|
|
+ }}
|
|
|
|
+ </Select>
|
|
|
|
+ </Form.Item>
|
|
|
|
+ <Form.Item label="征集日期">
|
|
|
|
+ <RangePicker
|
|
|
|
+ locale={dateLocal}
|
|
|
|
+ ranges={pickerRanges()}
|
|
|
|
+ value={time}
|
|
|
|
+ onChange={(datas: any) => {
|
|
|
|
+ if (datas) {
|
|
|
|
+ formState.startTime = dayjs(datas[0]);
|
|
|
|
+ formState.endTime = dayjs(datas[1]);
|
|
|
|
+ } else {
|
|
|
|
+ formState.startTime = undefined;
|
|
|
|
+ formState.endTime = undefined;
|
|
|
|
+ }
|
|
|
|
+ }}
|
|
|
|
+ />
|
|
|
|
+ </Form.Item>
|
|
|
|
+ <Form.Item style={{ marginBottom: 0 }} wrapperCol={{ span: 24 }}>
|
|
|
|
+ <Button block type="primary" htmlType="submit">
|
|
|
|
+ 确定
|
|
|
|
+ </Button>
|
|
|
|
+ </Form.Item>
|
|
|
|
+ </Form>
|
|
|
|
+ </div>
|
|
|
|
+ );
|
|
|
|
+ };
|
|
|
|
+ },
|
|
|
|
+});
|
|
|
|
+
|
|
|
|
+const ImageUploader = defineComponent({
|
|
|
|
+ props: {
|
|
|
|
+ data: string(),
|
|
|
|
+ icon: any(),
|
|
|
|
+ text: string().def(""),
|
|
|
|
+ },
|
|
|
|
+ emits: ["change"],
|
|
|
|
+ setup(props, { emit }) {
|
|
|
|
+ const uploadImage = async () => {
|
|
|
|
+ const url = await SelectOneImage();
|
|
|
|
+ if (!url) return;
|
|
|
|
+ emit("change", url);
|
|
|
|
+ };
|
|
|
|
+ return () => (
|
|
|
|
+ <div class={ImageStyle} onClick={uploadImage}>
|
|
|
|
+ <div class={"wapper"}>
|
|
|
|
+ {props.data ? (
|
|
|
|
+ <Image src={props.data} size={0} />
|
|
|
|
+ ) : (
|
|
|
|
+ <div class={"no_value"}>
|
|
|
|
+ {props.icon ? props.icon : <IconImage class={"text-30px"} />}
|
|
|
|
+ {props.text ? <div class={"up_txt"}>{props.text}</div> : null}
|
|
|
|
+ </div>
|
|
|
|
+ )}
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ );
|
|
|
|
+ },
|
|
|
|
+});
|
|
|
|
+const ImageStyle = css`
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 100%;
|
|
|
|
+ color: #fff;
|
|
|
|
+ background-color: #303030;
|
|
|
|
+ border-radius: 2px;
|
|
|
|
+ cursor: pointer;
|
|
|
|
+ .wapper {
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 100%;
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ justify-content: center;
|
|
|
|
+ }
|
|
|
|
+ .no_value {
|
|
|
|
+ display: inline-flex;
|
|
|
|
+ flex-direction: column;
|
|
|
|
+ align-items: center;
|
|
|
|
+ .up_txt {
|
|
|
|
+ margin-top: 10px;
|
|
|
|
+ font-size: 14px;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ img {
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 100%;
|
|
|
|
+ border-radius: 2px;
|
|
|
|
+ object-fit: cover;
|
|
|
|
+ }
|
|
|
|
+`;
|
|
|
|
+
|
|
|
|
+const ModalStyle = css`
|
|
|
|
+ width: 480px;
|
|
|
|
+ .ant-input-group.ant-input-group-compact {
|
|
|
|
+ display: flex;
|
|
|
|
+ }
|
|
|
|
+`;
|