Ver Fonte

Merge branch 'work' of http://124.70.149.18:10880/lianghj/queenshow into dev

bianjiang há 1 ano atrás
pai
commit
f538a96000
33 ficheiros alterados com 1229 adições e 98 exclusões
  1. 2 2
      src/App.tsx
  2. BIN
      src/assets/imgs/404.png
  3. BIN
      src/assets/imgs/empty_history.png
  4. BIN
      src/assets/imgs/icon_preview.png
  5. 23 4
      src/components/AssetsList.tsx
  6. 43 0
      src/components/responsiveObserve.ts
  7. 7 2
      src/modules/editor/components/CompUI/basicUI/Page/PageMusic.tsx
  8. 0 1
      src/modules/editor/components/CompUI/basicUI/Page/component.tsx
  9. 69 0
      src/modules/resource/actions/collection.tsx
  10. 0 1
      src/modules/resource/actions/editor.ts
  11. 7 1
      src/modules/resource/actions/index.ts
  12. 372 0
      src/modules/resource/components/CollectionEditModal.tsx
  13. 160 0
      src/modules/resource/components/CollectionListModal.tsx
  14. 4 0
      src/modules/resource/components/index.ts
  15. 17 0
      src/modules/resource/controllers/CollectionController.ts
  16. 0 24
      src/modules/resource/controllers/ComponentController.ts
  17. 0 19
      src/modules/resource/helper.ts
  18. 26 0
      src/modules/resource/http.ts
  19. 1 1
      src/pages/website/Material2/modal.tsx
  20. 39 20
      src/pages/website/MyCollection/components/CollectionItem.tsx
  21. 4 3
      src/pages/website/MyCollection/components/Header.tsx
  22. 14 7
      src/pages/website/MyCollection/components/index.tsx
  23. 39 0
      src/pages/website/MyCollection/controller.tsx
  24. 5 4
      src/pages/website/MyCollection/index.tsx
  25. 1 1
      src/pages/website/Promotion/components/Header.tsx
  26. 349 0
      src/pages/website/Promotion2/components/CollectionModal.tsx
  27. 1 1
      src/pages/website/Promotion2/components/Header.tsx
  28. 8 0
      src/pages/website/Promotion2/components/PromotionItem.tsx
  29. 27 0
      src/pages/website/Promotion2/components/SendPromotion.tsx
  30. 1 1
      src/pages/website/Promotion2/components/ShareModal.tsx
  31. 4 0
      src/pages/website/Promotion2/controller.tsx
  32. 3 3
      src/pages/website/components/layout/LeftContent.tsx
  33. 3 3
      src/pages/website/router.ts

+ 2 - 2
src/App.tsx

@@ -3,14 +3,14 @@ import { Provider } from "queenjs/adapter/vue";
 import { createApp, defineComponent } from "vue";
 import { Router } from "vue-router";
 import "./styles";
-
+import zh_cn from "ant-design-vue/es/locale/zh_CN";
 let setModuleHooks: any[] = [];
 
 const App = defineComponent(() => {
   setModuleHooks.forEach((hook) => hook());
   setModuleHooks = [];
   return () => (
-    <Provider>
+    <Provider locale={zh_cn}>
       <router-view></router-view>
     </Provider>
   );

BIN
src/assets/imgs/404.png


BIN
src/assets/imgs/empty_history.png


BIN
src/assets/imgs/icon_preview.png


+ 23 - 4
src/components/AssetsList.tsx

@@ -1,20 +1,39 @@
 import { List } from "@queenjs/ui";
 import { Empty, Pagination, Spin } from "ant-design-vue";
 import { defineUI } from "queenjs";
-import { any, number, string } from "vue-types";
-
+import { onUnmounted, reactive } from "vue";
+import { any, string } from "vue-types";
+import { responsiveObserve } from "./responsiveObserve";
 export default defineUI({
   props: {
-    columns: number().def(5),
+    columns: any().def(5),
     gap: string().def("15px"),
     item: any().isRequired,
     control: any().isRequired,
   },
   setup(props) {
+    // const state = reactive({
+    //   screen: "",
+    // });
+    // const mediaQuery = new responsiveObserve();
+    // mediaQuery.register((e: any) => {
+    //   console.log(e);
+    //   state.screen = e;
+    // });
+    // const colStyle = (columns: any) => {
+    //   const screen = state.screen;
+    //   const columnCount = columns[screen] ? columns[screen] : columns.column;
+    //   if (columnCount) {
+    //     return columnCount;
+    //   }
+    //   return columns || 5;
+    // };
+    // onUnmounted(() => {
+    //   mediaQuery.unregister();
+    // });
     return () => {
       const { control, columns, gap } = props;
       const loading = control.state.loading;
-
       return (
         <div>
           {loading && (

+ 43 - 0
src/components/responsiveObserve.ts

@@ -0,0 +1,43 @@
+const responsiveMap: { [key: string]: string } = {
+  xs: "(max-width: 575px)",
+  sm: "(min-width: 576px)",
+  md: "(min-width: 768px)",
+  lg: "(min-width: 992px)",
+  xl: "(min-width: 1200px)",
+  xxl: "(min-width: 1600px)",
+  xxxl: "(min-width: 2000px)",
+};
+
+export class responsiveObserve {
+  matchHandlers = {} as { [key: string]: any };
+  unregister() {
+    Object.keys(responsiveMap).forEach((screen) => {
+      const matchMediaQuery = responsiveMap[screen];
+      const handler = this.matchHandlers[matchMediaQuery];
+      if (handler) {
+        handler.mql.removeEventListener("change", handler.listener);
+      }
+    });
+    this.matchHandlers = {};
+  }
+  register(cb: any) {
+    Object.keys(responsiveMap).forEach((screen) => {
+      const matchMediaQuery = responsiveMap[screen];
+      const listener = (e: MediaQueryListEvent) => {
+        console.log(e);
+        if (e.matches) {
+          cb && cb(screen);
+        }
+      };
+      const mql = window.matchMedia(matchMediaQuery);
+      if (mql.matches) {
+        cb && cb(screen);
+      }
+      this.matchHandlers[matchMediaQuery] = {
+        mql: mql,
+        listener: listener,
+      };
+      mql.addEventListener("change", listener);
+    });
+  }
+}

+ 7 - 2
src/modules/editor/components/CompUI/basicUI/Page/PageMusic.tsx

@@ -11,6 +11,7 @@ import { css } from "@linaria/core";
 import { Button, Dropdown, Slider } from "ant-design-vue";
 import { Howl } from "howler";
 import { nanoid } from "nanoid";
+import { isPc } from "@queenjs/utils";
 import {
   defineComponent,
   reactive,
@@ -178,7 +179,12 @@ export const PageMusic = defineComponent({
     return () => {
       const music = rootComp?.value.music;
       return (
-        <div class={store.isEditMode ? MusicEditStyle : MusicStyle}>
+        <div
+          class={[
+            store.isEditMode ? MusicEditStyle : MusicStyle,
+            isPc() ? "absolute" : "fixed",
+          ]}
+        >
           {store.isEditMode ? (
             <AudioPlayer
               key={music}
@@ -399,7 +405,6 @@ const AudioPlayerStyle = css`
   }
 `;
 const MusicStyle = css`
-  position: fixed;
   top: 10px;
   right: 10px;
   z-index: 999;

+ 0 - 1
src/modules/editor/components/CompUI/basicUI/Page/component.tsx

@@ -15,7 +15,6 @@ export const Component = defineComponent({
     const editor = useEditor();
     const { helper } = editor;
     const compRef = useCompRef(props.compId);
-
     return () => {
       const { children, layout, value } = useCompData(props.compId);
       const compMusic = value.music || "";

+ 69 - 0
src/modules/resource/actions/collection.tsx

@@ -0,0 +1,69 @@
+import { queenApi } from "queenjs";
+import { ResourceModule } from "..";
+
+export const collectionAction = ResourceModule.action({
+  async deleteCollection(record: any) {
+    const res = await queenApi.showConfirm({
+      content: `删除后无法恢复,确定要删除:${record.title}?`,
+      type: "danger",
+    });
+    if (!res) return;
+    await this.https.deleteCollection(record._id);
+  },
+
+  async createOrUpdateCollection(record: any) {
+    const data = await this.showModal(
+      <this.components.CollectionEditModal record={record} />
+    );
+    if (record && record._id) {
+      await this.https.updateCollection(data);
+    } else {
+      await this.https.createCollection(data);
+    }
+  },
+  async showCollectionList(record: any) {
+    this.showModal(<this.components.CollectionListModal record={record} />, {
+      title: `${record.title}作品集`,
+      fullscreen: true,
+    });
+  },
+  async collectionDTL(id: string) {
+    const res = await this.https.detailCollection(id);
+    if (res.errorNo != 200) {
+      return;
+    }
+    return res.result;
+  },
+  async searchCollection(key: string, commitId: string) {
+    try {
+      const res = await this.https.searchCollection({ key, commitId });
+      return res.result;
+    } catch (e) {
+      queenApi.messageError("未查询到接收地址数据!");
+    }
+  },
+  async commitCollection(data: any) {
+    try {
+      const res = await this.https.commitCollection(data);
+      return res.result;
+    } catch (e) {
+      console.log(e);
+    }
+  },
+  async getCommitHistoryDetail(id: string) {
+    try {
+      const res = await this.https.commitHistoryDetail(id);
+      return res.result;
+    } catch (e) {
+      queenApi.messageError("未查询到数据!");
+    }
+  },
+  async updateCommitData(data: any) {
+    try {
+      const res = await this.https.updateCommitData(data);
+      return res.result;
+    } catch (e) {
+      console.log(e);
+    }
+  },
+});

+ 0 - 1
src/modules/resource/actions/editor.ts

@@ -22,7 +22,6 @@ export const editorActions = ResourceModule.action({
 
   async submitRender(id: string, images: any, videos: any) {
     queenApi.showLoading("任务提交中");
-
     console.log("iamges=>", images, "videos->", videos);
 
     try {

+ 7 - 1
src/modules/resource/actions/index.ts

@@ -1,5 +1,11 @@
 import { editorActions } from "./editor";
 import { materialActions } from "./material";
 import { promotionAction } from "./promotion";
+import { collectionAction } from "./collection";
 
-export const actions = [editorActions, materialActions, promotionAction];
+export const actions = [
+  editorActions,
+  materialActions,
+  promotionAction,
+  collectionAction,
+];

+ 372 - 0
src/modules/resource/components/CollectionEditModal.tsx

@@ -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;
+  }
+`;

+ 160 - 0
src/modules/resource/components/CollectionListModal.tsx

@@ -0,0 +1,160 @@
+import { css, cx } from "@linaria/core";
+import { defineComponent, onMounted } from "vue";
+import { any } from "vue-types";
+import List from "@/components/AssetsList";
+import { PageListController } from "@queenjs/controllers";
+import { defineUI } from "queenjs";
+import { Image, View } from "@queenjs/ui";
+import { useResource } from "..";
+import dayjs from "dayjs";
+import { useEditor } from "@/modules/editor";
+import { Select } from "ant-design-vue";
+export default defineComponent({
+  props: {
+    record: any(),
+  },
+  setup(props, { emit }) {
+    const resource = useResource();
+    const editor = useEditor();
+    const ListCtrl = new PageListController(resource.config?.httpConfig);
+    ListCtrl.setCrudPrefix("/wk/h5");
+    ListCtrl.state.query = { id: props.record._id };
+    onMounted(() => {
+      ListCtrl.loadPage(1);
+    });
+    const previewInModal = async (id: string, title: string) => {
+      if (!id) {
+        return;
+      }
+      const ret = await resource.actions.getCommitHistoryDetail(id);
+      if (!ret) {
+        return;
+      }
+      editor.store.setDesignData(ret);
+      editor.actions.switchMode("preview");
+      resource.showModal(
+        <div class={"!p-0"}>
+          <div class={"h-600px scrollbar"}>
+            <editor.components.Preview class="pointer-events-none" />
+          </div>
+        </div>,
+        {
+          title: title,
+          destroyOnClose: true,
+        }
+      );
+    };
+
+    return () => {
+      return (
+        <div>
+          <List
+            gap="24px"
+            class={"p-24px h-full scrollbar"}
+            columns={6}
+            control={ListCtrl}
+            item={(item: any) => (
+              <ListItem
+                item={item}
+                record={props.record}
+                onPreview={(id, title) => {
+                  previewInModal(id, title);
+                }}
+                onEdit={async (record) => {
+                  await resource.actions.updateCommitData(record);
+                  ListCtrl.fresh();
+                }}
+              />
+            )}
+          />
+        </div>
+      );
+    };
+  },
+});
+const ListItem = defineUI({
+  props: {
+    item: any(),
+    record: any(),
+  },
+  emits: ["edit", "preview"],
+  setup(props, { emit }) {
+    return () => {
+      const { item, record } = props;
+      const h5 = item.h5[0] || {};
+      const wks = item.wks || {};
+      const options = record?.flags?.map((e: string) => {
+        return { label: e, value: e };
+      });
+      return (
+        <div class={cx(itemStyles, "relative")}>
+          <View ratio={1} class="overflow-hidden relative">
+            <Image
+              class="h-1/1 w-1/1 !object-contain bg-[#ebebeb]"
+              src={h5?.thumbnail}
+            />
+            <div class="absolute inset-0 flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity">
+              <div
+                class="text-white icon_action w-60px leading-60px orange cursor-pointer rounded-1/2 text-center transition-opacity hover:opacity-90 active:opacity-80"
+                onClick={() => emit("preview", wks.id, h5?.title)}
+              >
+                查看
+              </div>
+            </div>
+            {record.flags && record.flags.length > 0 && (
+              <div class={"select_box w-80px"}>
+                <Select
+                  class={"w-full"}
+                  value={wks.flag}
+                  options={options}
+                  onChange={(v) => {
+                    wks.flag = v;
+                    emit("edit", {
+                      id: record._id,
+                      wkId: wks.id,
+                      flag: wks.flag,
+                    });
+                  }}
+                ></Select>
+              </div>
+            )}
+          </View>
+          <div class="item_footer rounded-b-4px flex items-center justify-between p-15px">
+            <div class="flex-1 w-0">
+              <div class="text-white text-bold truncate">{h5?.title}</div>
+              <div class="flex items-center text-opacity-60 text-white text-12px mt-5px">
+                {dayjs(wks.commitTime).format("YYYY.MM.DD")} 提交
+              </div>
+            </div>
+          </div>
+        </div>
+      );
+    };
+  },
+});
+const itemStyles = css`
+  .item_footer {
+    background: #414141;
+  }
+  .icon_action {
+    background-color: rgba(0, 0, 0, 0.8);
+    &.orange {
+      background-color: rgba(232, 139, 0, 0.8);
+    }
+  }
+  .select_box {
+    position: absolute;
+    left: 10px;
+    top: 10px;
+    .ant-select {
+      font-size: 12px;
+      .ant-select-selector {
+        height: 24px;
+        background-color: @inf-component-bg;
+        .ant-select-selection-item {
+          line-height: 22px;
+        }
+      }
+    }
+  }
+`;

+ 4 - 0
src/modules/resource/components/index.ts

@@ -1,9 +1,13 @@
 import MaterialItem from "./MaterialItem";
 import PromotionItem from "./PromotionItem";
 import ResourceManager from "./ResourceManager";
+import CollectionEditModal from "./CollectionEditModal";
+import CollectionListModal from "./CollectionListModal";
 
 export const compoents = {
   MaterialItem,
   PromotionItem,
   ResourceManager,
+  CollectionEditModal,
+  CollectionListModal,
 };

+ 17 - 0
src/modules/resource/controllers/CollectionController.ts

@@ -0,0 +1,17 @@
+import { PageListController } from "@queenjs/controllers";
+
+export class CollectionController {
+  ListCtrl = new PageListController<any, any>();
+  createCollection() {
+    console.log("createCollection");
+  }
+  onMenuClick(menu: string, item: any) {
+    console.log("onMenuClick", menu, item);
+  }
+  onEdit(item: any) {
+    console.log(item);
+  }
+  onPreview(item: any) {
+    console.log(item);
+  }
+}

+ 0 - 24
src/modules/resource/controllers/ComponentController.ts

@@ -1,24 +0,0 @@
-import { PageListController } from "@queenjs/controllers";
-
-export class ComponentController {
-  ListCtrl = new PageListController<any, any>();
-  createComp() {
-    console.log("createPromotion");
-  }
-  onMenuClick(menu: string, item: any) {
-    console.log("onMenuClick", menu, item);
-  }
-  onEdit(item: any) {
-    const _params = new URLSearchParams(decodeURIComponent(location.search));
-    const host = _params.get("host");
-
-    // if (location.host == "www.infish.cn") {
-    //   const url = `${location.origin}/projects/queenshowv1/editor.html?host=${host}#/?id=${item._id}&mode=editComp`;
-    //   location.href = url;
-    //   return;
-    // }
-
-    const url = `${location.origin}/editor.html?host=${host}#/?id=${item._id}&mode=editComp`;
-    location.href = url;
-  }
-}

+ 0 - 19
src/modules/resource/helper.ts

@@ -1,7 +1,5 @@
-import { PageListController } from "@queenjs/controllers";
 import { queenApi } from "queenjs";
 import { ResourceModule } from ".";
-import { ComponentController } from "./controllers/ComponentController";
 
 export const helper = ResourceModule.helper({
   createFileName(fileName: string, dir: string) {
@@ -14,23 +12,6 @@ export const helper = ResourceModule.helper({
     )}_${fileName}`;
   },
 
-  createCompController() {
-    const ctrl = new ComponentController();
-    ctrl.ListCtrl = new PageListController(this.config?.httpConfig);
-    ctrl.ListCtrl.setCrudPrefix("/frame");
-    ctrl.createComp = this.actions.createComp;
-    ctrl.onMenuClick = async (name, record) => {
-      if (name == "delete") {
-        await this.actions.deleteComp(record);
-        ctrl.ListCtrl.fresh();
-      } else if (name == "rename") {
-        await this.actions.renameComp(record);
-      }
-    };
-
-    return ctrl;
-  },
-
   // createSourceController() {
   //   const { controls, actions } = this;
 

+ 26 - 0
src/modules/resource/http.ts

@@ -46,6 +46,32 @@ export const http = ResourceModule.http({
   deleteComp(id: string) {
     return this.request(`/frame/delete/${id}`, { method: "POST" });
   },
+  //collection
+  createCollection(data: any) {
+    return this.request("/works/create", { method: "POST", data });
+  },
+
+  updateCollection(data: any) {
+    return this.request("/works/update", { method: "POST", data });
+  },
+  deleteCollection(id: string) {
+    return this.request(`/works/delete/${id}`, { method: "POST" });
+  },
+  detailCollection(id: string) {
+    return this.request(`/works/detail/${id}`, { method: "GET" });
+  },
+  searchCollection(params: any) {
+    return this.request("/works/search", { method: "GET", params });
+  },
+  commitCollection(data: any) {
+    return this.request("/works/commit", { method: "POST", data });
+  },
+  commitHistoryDetail(id: any) {
+    return this.request(`/wk/h5/detail/${id}`, { method: "GET" });
+  },
+  updateCommitData(data: any) {
+    return this.request("/wk/update/flag", { method: "POST", data });
+  },
 });
 
 /**

+ 1 - 1
src/pages/website/Material2/modal.tsx

@@ -38,5 +38,5 @@ export async function SelectOneImage() {
 }
 
 export async function SelectOneVideo() {
-  return  await queenApi.dialog(<SelectMaterialDialog type="image" />,  {title:"选择单个视频", width: "900px"})
+  return  await queenApi.dialog(<SelectMaterialDialog type="video" />,  {title:"选择单个视频", width: "900px"})
 }

+ 39 - 20
src/pages/website/MyComps/components/CompItem.tsx → src/pages/website/MyCollection/components/CollectionItem.tsx

@@ -1,4 +1,5 @@
 import { css, cx } from "@linaria/core";
+import Select from "@queenjs-modules/queditor/components/FormUI/Items/Select";
 import { IconMore } from "@queenjs/icons";
 import { Image, View } from "@queenjs/ui";
 import { Dropdown, Menu } from "ant-design-vue";
@@ -14,28 +15,34 @@ export default defineUI({
   setup(props, { emit }) {
     return () => {
       const { record } = props;
+      const options = record?.statues?.map((e: string) => {
+        return { label: e, value: e };
+      });
       return (
         <div class={cx(itemStyles, "relative")}>
           <View ratio={1.4} class=" relative">
-            <Image
-              class="h-1/1 w-1/1 !object-contain bg-[#ebebeb]"
-              src={record?.thumbnail}
-            />
-            {/* <Tag
-              color="#E88B00"
-              // color="rgba(0, 0, 0, 0.4)"
-              class="absolute top-0 left-0 z-1 !rounded-none"
-            >
-              未发布
-            </Tag> */}
-            {/* <div class="absolute inset-0 flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity">
+            <Image class="h-1/1 w-1/1  bg-[#ebebeb]" src={record?.cover} />
+            <div class="absolute inset-0 flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity">
               <div
-                class="text-white icon_action w-60px leading-60px orange cursor-pointer rounded-1/2 text-center"
-                onClick={() => emit("edit", props.record)}
+                class="text-white icon_action w-60px leading-60px  cursor-pointer rounded-1/2 text-center transition-opacity hover:opacity-90 active:opacity-80"
+                onClick={() => emit("preview", record)}
               >
-                编辑
+                查看
+              </div>
+            </div>
+            {record.statues && record.statues.length > 0 && (
+              <div class={"select_box w-80px"}>
+                <Select
+                  class={"w-full"}
+                  value={record.status}
+                  options={options}
+                  onChange={(v) => {
+                    record.status = v;
+                    emit("edit", record);
+                  }}
+                ></Select>
               </div>
-            </div> */}
+            )}
           </View>
           <div class="item_footer rounded-b-4px flex items-center justify-between p-15px">
             <div class="w-0 flex-1">
@@ -49,7 +56,7 @@ export default defineUI({
               overlay={
                 <Menu class="w-90px">
                   <Menu.Item>
-                    <div onClick={() => emit("menu", "rename")}>重命名</div>
+                    <div onClick={() => emit("menu", "update")}>编辑</div>
                   </Menu.Item>
                   <Menu.Item>
                     <div onClick={() => emit("menu", "delete")}>删除</div>
@@ -71,9 +78,21 @@ const itemStyles = css`
     background: #414141;
   }
   .icon_action {
-    background-color: rgba(0, 0, 0, 0.5);
-    &.orange {
-      background-color: rgba(232, 139, 0, 0.5);
+    background-color: rgba(0, 0, 0, 0.8);
+  }
+  .select_box {
+    position: absolute;
+    left: 10px;
+    top: 10px;
+    .ant-select {
+      font-size: 12px;
+      .ant-select-selector {
+        height: 24px;
+        background-color: @inf-component-bg;
+        .ant-select-selection-item {
+          line-height: 22px;
+        }
+      }
     }
   }
 `;

+ 4 - 3
src/pages/website/MyComps/components/Header.tsx → src/pages/website/MyCollection/components/Header.tsx

@@ -1,3 +1,4 @@
+import { Button } from "ant-design-vue";
 import { defineUI } from "queenjs";
 
 export default defineUI({
@@ -5,10 +6,10 @@ export default defineUI({
   setup(props, { emit }) {
     return () => (
       <div class="flex items-center justify-between">
-        <h3 class="text-22px">我的组件</h3>
-        {/* <Button type="primary" onClick={()=>emit("add")}>
+        <h3 class="text-22px">作品集</h3>
+        <Button type="primary" onClick={() => emit("add")}>
           新增+
-        </Button> */}
+        </Button>
       </div>
     );
   },

+ 14 - 7
src/pages/website/MyComps/components/index.tsx → src/pages/website/MyCollection/components/index.tsx

@@ -1,14 +1,14 @@
 import List from "@/components/AssetsList";
-import { ComponentController } from "@/modules/resource/controllers/ComponentController";
+import { CollectionController } from "@/modules/resource/controllers/CollectionController";
 import { defineUI } from "queenjs";
 import { onMounted } from "vue";
 import { any } from "vue-types";
-import CompItem from "./CompItem";
+import CollectionItem from "./CollectionItem";
 import Header from "./Header";
 
 export default defineUI({
   props: {
-    Controller: any<ComponentController>().isRequired,
+    Controller: any<CollectionController>().isRequired,
   },
   slots: {
     Header,
@@ -22,19 +22,26 @@ export default defineUI({
     return () => {
       return (
         <div>
-          <slots.Header onAdd={props.Controller.createComp} />
+          <slots.Header
+            onAdd={() => {
+              props.Controller.createCollection();
+            }}
+          />
           <slots.List
             gap="25px"
             class="my-30px"
-            columns={4}
+            columns={5}
             control={props.Controller.ListCtrl}
             item={(record: any) => (
-              <CompItem
+              <CollectionItem
                 record={record}
                 onMenu={(name) => {
                   props.Controller.onMenuClick(name, record);
                 }}
-                onEdit={(record) => props.Controller.onEdit(record)}
+                onEdit={(record) => {
+                  props.Controller.onEdit(record);
+                }}
+                onPreview={(record) => props.Controller.onPreview(record)}
               />
             )}
           />

+ 39 - 0
src/pages/website/MyCollection/controller.tsx

@@ -0,0 +1,39 @@
+import { ResourceModule } from "@/modules/resource";
+import { CollectionController } from "@/modules/resource/controllers/CollectionController";
+import { PageListController } from "@queenjs/controllers";
+
+export function createCollectionController(resource: ResourceModule) {
+  const ctrl = new CollectionController();
+
+  ctrl.ListCtrl = new PageListController(resource.config?.httpConfig);
+  ctrl.ListCtrl.setCrudPrefix("/works");
+
+  ctrl.createCollection = async () => {
+    await resource.actions.createOrUpdateCollection(null);
+    ctrl.ListCtrl.fresh();
+  };
+  ctrl.onPreview = (record: any) => {
+    resource.actions.showCollectionList(record);
+  };
+  ctrl.onMenuClick = async (name: string, record: any) => {
+    if (name == "delete") {
+      await resource.actions.deleteCollection(record);
+      ctrl.ListCtrl.fresh();
+    } else if (name == "update") {
+      if (!record._id) {
+        return;
+      }
+      const detail = await resource.actions.collectionDTL(record._id);
+      await resource.actions.createOrUpdateCollection(detail);
+      ctrl.ListCtrl.fresh();
+    }
+  };
+  ctrl.onEdit = async (record: any) => {
+    if (!record._id) {
+      return;
+    }
+    await resource.https.updateCollection(record);
+    ctrl.ListCtrl.fresh();
+  };
+  return ctrl;
+}

+ 5 - 4
src/pages/website/MyComps/index.tsx → src/pages/website/MyCollection/index.tsx

@@ -1,13 +1,14 @@
 import { useResource } from "@/modules/resource";
 import { defineComponent } from "vue";
 
-import PromotionUI from "./components";
+import CollectionUI from "./components";
+import { createCollectionController } from "./controller";
 export default defineComponent({
   setup() {
     const resource = useResource();
-    const ctrl = resource.helper.createCompController();
+    const ctrl = createCollectionController(resource);
     return () => (
-      <PromotionUI
+      <CollectionUI
         Controller={ctrl}
         slots={
           {
@@ -16,7 +17,7 @@ export default defineComponent({
             // }
           }
         }
-      ></PromotionUI>
+      ></CollectionUI>
     );
   },
 });

+ 1 - 1
src/pages/website/Promotion/components/Header.tsx

@@ -8,7 +8,7 @@ export default defineComponent({
 
     return () => (
       <div class="flex items-center justify-between">
-        <h3 class="text-22px">我的推广</h3>
+        <h3 class="text-22px">我的作品</h3>
         <Button type="primary" onClick={resource.actions.createPromotion}>
           新增+
         </Button>

+ 349 - 0
src/pages/website/Promotion2/components/CollectionModal.tsx

@@ -0,0 +1,349 @@
+import { css } from "@linaria/core";
+
+import { Button, Input, Select } from "ant-design-vue";
+import { SearchOutlined } from "@ant-design/icons-vue";
+import { defineComponent, reactive } from "vue";
+import { any } from "vue-types";
+import { Image } from "@queenjs/ui";
+import { useResource } from "@/modules/resource";
+
+import dayjs from "dayjs";
+import { queenApi, useModal } from "queenjs";
+import { useEditor } from "@/modules/editor";
+export default defineComponent({
+  props: {
+    record: any().isRequired,
+  },
+  setup(props, { slots }) {
+    const resource = useResource();
+    const state = reactive({
+      currCollection: {} as any,
+      searchVal: "",
+    });
+    const editor = useEditor();
+    const modal = useModal();
+    const EmptyHistory = () => {
+      return (
+        <div
+          class={
+            "inline-flex flex-col items-center justify-center w-full h-full  rounded-6px"
+          }
+          style={{ background: "#F1F2F4" }}
+        >
+          <div>
+            <img
+              width={86}
+              height={66}
+              src={require("@/assets/imgs/empty_history.png")}
+            />
+          </div>
+          <div class={"text-12px mt-16px text-gray"}>暂无历史发送信息</div>
+        </div>
+      );
+    };
+    const EmptyCollection = () => {
+      return (
+        <div class={"text-center"}>
+          <div
+            class={
+              "w-full h-290px inline-flex flex-col items-center justify-center rounded-6px"
+            }
+            style={{ background: "#F1F2F4" }}
+          >
+            <img
+              class={"object-contain"}
+              width={200}
+              height={142}
+              src={require("@/assets/imgs/404.png")}
+            />
+          </div>
+          <div class={"text-12px mt-18px text-gray"}>
+            请输入正确的接收地址以获取信息
+          </div>
+        </div>
+      );
+    };
+    const workPreview = async (currId: string) => {
+      await editor.actions.initDesign(currId, false);
+      previewInModal("当前提交");
+    };
+    const historyPreview = async (hisId: string) => {
+      const ret = await resource.actions.getCommitHistoryDetail(hisId);
+      if (!ret) {
+        return;
+      }
+      editor.store.setDesignData(ret);
+      previewInModal("历史提交");
+    };
+    const collectionPreview = async (collection: any) => {
+      if (collection.introLink) {
+        window.open(collection.introLink);
+        return;
+      }
+      if (collection.introH5Id) {
+        await editor.actions.initDesign(collection.introH5Id, false);
+        previewInModal("详情介绍");
+      }
+    };
+    const previewInModal = (title: string) => {
+      editor.actions.switchMode("preview");
+      resource.showModal(
+        <div class={"!p-0"}>
+          <div class={"h-600px scrollbar"}>
+            <editor.components.Preview class="pointer-events-none" />
+          </div>
+        </div>,
+        {
+          title: title,
+          destroyOnClose: true,
+        }
+      );
+    };
+    const itemRender = (data: any) => {
+      return (
+        <div class={"flex h-full overflow-hidden"}>
+          <div class={[itemPreview, "relative"]}>
+            <Image class="w-160px h-160px rounded-6px" src={data?.thumbnail} />
+            <div
+              class={"icon_preview absolute top-8px right-8px"}
+              onClick={() => workPreview(data._id)}
+            >
+              <img
+                class={"w-20px h-20px"}
+                src={require("@/assets/imgs/icon_preview.png")}
+              />
+            </div>
+          </div>
+
+          <div class={"flex-1 pl-20px  flex flex-col"}>
+            <div class={"text-18px"}>{data.title}</div>
+            <div class={"my-12px text-gray break-all flex-1 overflow-hidden"}>
+              {data.desc}
+            </div>
+          </div>
+        </div>
+      );
+    };
+    const itemHistory = () => {
+      if (!state.currCollection.h5) {
+        return null;
+      }
+      const h5 = state.currCollection.h5[0];
+      const wks = state.currCollection.wks;
+      return (
+        <div class={"flex h-full overflow-hidden"}>
+          <div class={[itemPreview, "relative"]}>
+            <Image class="w-160px h-160px rounded-6px" src={h5.thumbnail} />
+            <div
+              class={"icon_preview absolute top-8px right-8px"}
+              onClick={() => historyPreview(wks.id)}
+            >
+              <img
+                class={"w-20px h-20px"}
+                src={require("@/assets/imgs/icon_preview.png")}
+              />
+            </div>
+          </div>
+          <div class={"flex-1 pl-20px flex flex-col"}>
+            <div class={"text-18px"}>{h5.title}</div>
+            <div class={"my-12px text-gray break-all flex-1 overflow-hidden"}>
+              {h5.desc}
+            </div>
+            <div class={"text-12px text-gray"}>
+              提交日期:{dayjs(wks.endTime).format("YYYY-MM-DD")}
+            </div>
+          </div>
+        </div>
+      );
+    };
+    const CollectionRender = () => {
+      const data = state.currCollection;
+      return (
+        <div>
+          <div class={"text-18px mb-20px"}>{data.title}</div>
+          <div class={[itemPreview, "w-full h-290px rounded-6px relative"]}>
+            <Image class={"w-full h-full rounded-6px"} src={data.cover} />
+            {(data.introLink || data.introH5Id) && (
+              <div
+                class={"icon_preview absolute top-10px right-10px"}
+                onClick={() => {
+                  collectionPreview(data);
+                }}
+              >
+                <img
+                  class={"w-30px h-30px"}
+                  src={require("@/assets/imgs/icon_preview.png")}
+                />
+              </div>
+            )}
+          </div>
+          <div class={"flex justify-between items-center mt-15px"}>
+            <div>
+              {data.logo && (
+                <Image
+                  class={"w-42px h-42px object-cover rounded-2px"}
+                  src={data.logo}
+                />
+              )}
+              {data.endTime && (
+                <span class={"pl-20px text-gray"}>
+                  截止日期:{dayjs(data.endTime).format("YYYY-MM-DD")}
+                </span>
+              )}
+            </div>
+            {data.status && (
+              <div
+                class={
+                  "text-16px text-white bg-blue-500 px-20px py-10px rounded-4px"
+                }
+              >
+                {data.status}
+              </div>
+            )}
+          </div>
+        </div>
+      );
+    };
+    const search = async () => {
+      if (!state.searchVal) {
+        return false;
+      }
+      const collection = await resource.actions.searchCollection(
+        state.searchVal,
+        props.record._id
+      );
+      if (!collection) {
+        return;
+      }
+      state.currCollection = collection[0];
+    };
+    const commit = async () => {
+      const res = await resource.actions.commitCollection({
+        id: state.currCollection._id,
+        h5Id: props.record._id,
+      });
+      if (!res) {
+        return;
+      }
+      modal.submit();
+      queenApi.messageSuccess("发送成功");
+    };
+    return () => {
+      return (
+        <div class={ModalStyle}>
+          <div class={"space-y-14px"}>
+            <div
+              class={"flex items-center bg-white px-30px py-18px rounded-6px"}
+            >
+              <div class={"text-16px"}>接收地址</div>
+              <div class={"flex-1 px-30px"}>
+                <Input
+                  class={"w-full text-center"}
+                  placeholder={"请输入接收地址"}
+                  value={state.searchVal}
+                  onChange={(e) => {
+                    state.searchVal = e.target.value || "";
+                  }}
+                ></Input>
+              </div>
+              <div>
+                <Button
+                  type="primary"
+                  ghost
+                  icon={<SearchOutlined />}
+                  onClick={search}
+                >
+                  查询
+                </Button>
+              </div>
+            </div>
+            <div class={"bg-white px-30px py-20px"}>
+              {state.currCollection._id
+                ? CollectionRender()
+                : EmptyCollection()}
+            </div>
+            <div class={"flex items-center space-x-16px"}>
+              <div class={"flex-1 bg-white px-30px py-18px rounded-6px"}>
+                <div class={"text-16px"}>当前发送</div>
+                <div class={"mt-20px h-160px"}>{itemRender(props.record)}</div>
+              </div>
+              <div class={"flex-1 bg-white px-30px py-18px rounded-6px"}>
+                <div class={"text-16px"}>历史发送</div>
+                <div class={"mt-20px h-160px"}>
+                  {state.currCollection.h5 ? itemHistory() : EmptyHistory()}
+                </div>
+              </div>
+            </div>
+          </div>
+          <div class={"text-center mt-24px"}>
+            <Button
+              type="primary"
+              ghost
+              size={"large"}
+              class={"w-240px"}
+              disabled={state.currCollection._id ? false : true}
+              onClick={commit}
+            >
+              确认发送
+            </Button>
+          </div>
+        </div>
+      );
+    };
+  },
+});
+const itemPreview = css`
+  &:hover {
+    .icon_preview {
+      opacity: 1;
+    }
+  }
+  .icon_preview {
+    opacity: 0;
+    cursor: pointer;
+  }
+`;
+const ModalStyle = css`
+  color: #111;
+  .ant-input {
+    border-radius: 4px;
+    border-color: rgba(51, 51, 51, 0.3);
+    color: #111;
+    &::placeholder {
+      color: #999;
+    }
+  }
+  .ant-select:not(.ant-select-customize-input) {
+    .ant-select-selector {
+      border-radius: 4px;
+      border-color: rgba(51, 51, 51, 0.3);
+      color: #111;
+      .ant-select-selection-search {
+        input {
+          text-align: center;
+        }
+      }
+    }
+  }
+  .ant-select-selection-placeholder {
+    color: #999;
+  }
+  .ant-btn-background-ghost.ant-btn-primary {
+    border-radius: 4px;
+    background-color: rgba(255, 227, 178, 0.3);
+  }
+  .ant-btn-background-ghost.ant-btn-primary[disabled] {
+    color: #fff;
+    border-color: transparent;
+    background: #ccc;
+    text-shadow: none;
+    box-shadow: none;
+    &:hover {
+      color: #fff;
+      border-color: transparent;
+      background: #ccc;
+      text-shadow: none;
+      box-shadow: none;
+    }
+  }
+`;

+ 1 - 1
src/pages/website/Promotion2/components/Header.tsx

@@ -8,7 +8,7 @@ export default defineUI({
     
     return () => (
       <div class="flex items-center justify-between">
-        <h3 class="text-22px">我的推广</h3>
+        <h3 class="text-22px">我的作品</h3>
         <Button type="primary" onClick={()=>emit("add")}>
           新增+
         </Button>

+ 8 - 0
src/pages/website/Promotion2/components/PromotionItem.tsx

@@ -88,6 +88,14 @@ export default defineUI({
               placement="bottom"
               overlay={
                 <Menu class="w-90px">
+                  {/* <Menu.Item>复制</Menu.Item> */}
+                  <Menu.Item
+                    onClick={() => {
+                      emit("menu", "send");
+                    }}
+                  >
+                    发送作品到
+                  </Menu.Item>
                   <Menu.Item>
                     <div onClick={() => emit("menu", "stat")}>统计分析</div>
                   </Menu.Item>

+ 27 - 0
src/pages/website/Promotion2/components/SendPromotion.tsx

@@ -0,0 +1,27 @@
+import { ResourceModule } from "@/modules/resource";
+import CollectionModal from "./CollectionModal";
+import { css } from "@linaria/core";
+
+export function sendPromotion(resource: ResourceModule, record: any) {
+  resource.showModal(<CollectionModal record={record}></CollectionModal>, {
+    title: "发送作品",
+    width: "860px",
+    destroyOnClose: true,
+    wrapClassName: CollectionStyle,
+  });
+}
+const CollectionStyle = css`
+  .ant-modal-content {
+    background-color: transparent;
+    border-radius: 4px;
+  }
+  .ant-modal-header {
+    padding: 16px 24px;
+    background-color: #2a2d41;
+    border-radius: 4px 4px 0 0;
+  }
+  .ant-modal-body {
+    background-color: #f1f2f4;
+    border-radius: 0 0 4px 4px;
+  }
+`;

+ 1 - 1
src/pages/website/Promotion2/components/ShareModal.tsx

@@ -43,7 +43,7 @@ export default defineComponent({
       return (
         <div class="flex items-start">
           <div>
-            <div class="scrollbar h-600px overflow-y-auto border-1px border-solid border-dark-50">
+            <div class="scrollbar h-600px relative overflow-y-auto border-1px border-solid border-dark-50">
               {slots.preview?.()}
             </div>
             <div class="mt-20px text-center">

+ 4 - 0
src/pages/website/Promotion2/controller.tsx

@@ -4,6 +4,7 @@ import { PromotionController } from "@/modules/resource/controllers/PromotionCon
 import { PageListController } from "@queenjs/controllers";
 import { queenApi } from "queenjs";
 import ShareModal from "./components/ShareModal";
+import { sendPromotion } from "./components/SendPromotion";
 import { AuthModule } from "@queenjs-modules/auth";
 
 export function createPromotinController(
@@ -71,6 +72,9 @@ export function createPromotinController(
       case "share":
         sharePromotion(record);
         break;
+      case "send":
+        sendPromotion(resource, record);
+        break;
     }
   };
 

+ 3 - 3
src/pages/website/components/layout/LeftContent.tsx

@@ -33,13 +33,13 @@ export default defineUI({
     const menuOptions = [
       {
         link: "/workbench/promotion",
-        label: "我的推广",
+        label: "我的作品",
         icon: IconDashboard,
         // suffix: "7",
       },
       {
-        link: "/workbench/myComps",
-        label: "我的组件",
+        link: "/workbench/collection",
+        label: "作品集",
         icon: IconCube,
         // suffix: "32",
       },

+ 3 - 3
src/pages/website/router.ts

@@ -33,9 +33,9 @@ const routes: Array<RouteRecordRaw> = [
         component: () => import("./Promotion2"),
       },
       {
-        path: "/workbench/myComps",
-        name: "myComps",
-        component: () => import("./MyComps"),
+        path: "/workbench/collection",
+        name: "collection",
+        component: () => import("./MyCollection"),
       },
       {
         path: "/workstage/material",