Browse Source

Merge branch 'master' of http://124.70.149.18:10880/lianghj/queenshow

liwei 1 year ago
parent
commit
351bdee982

+ 11 - 2
package.json

@@ -15,6 +15,15 @@
     "deploy": "npm run build && npm run uploadOss && npm run uploadServer"
   },
   "dependencies": {
+    "@ckeditor/ckeditor5-alignment": "^38.0.0",
+    "@ckeditor/ckeditor5-basic-styles": "^38.0.0",
+    "@ckeditor/ckeditor5-editor-inline": "^38.0.0",
+    "@ckeditor/ckeditor5-essentials": "^38.0.0",
+    "@ckeditor/ckeditor5-font": "^38.0.0",
+    "@ckeditor/ckeditor5-link": "^38.0.0",
+    "@ckeditor/ckeditor5-paragraph": "^38.0.0",
+    "@ckeditor/ckeditor5-theme-lark": "^38.0.0",
+    "@ckeditor/ckeditor5-vue": "^5.1.0",
     "@linaria/core": "^4.1.1",
     "@queenjs-modules/auth": "^0.0.18",
     "@queenjs-modules/queditor": "^0.0.11",
@@ -48,7 +57,6 @@
     "proto.gl": "^1.0.0",
     "queen3d": "^0.0.80",
     "queenjs": "^1.0.0-beta.72",
-    "quill": "^1.3.7",
     "rimraf": "^3.0.2",
     "scp2": "^0.5.0",
     "swiper": "^8.4.4",
@@ -59,12 +67,13 @@
     "vue-types": "^4.2.1"
   },
   "devDependencies": {
+    "@ckeditor/ckeditor5-dev-translations": "^37.0.1",
+    "@ckeditor/ckeditor5-dev-utils": "^37.0.1",
     "@linaria/babel-preset": "^4.1.2",
     "@linaria/webpack-loader": "^4.1.2",
     "@queenjs/webpack-loader": "^0.0.2",
     "@types/color-convert": "^2.0.0",
     "@types/lodash": "^4.14.186",
-    "@types/quill": "^2.0.10",
     "@types/three": "^0.146.0",
     "@typescript-eslint/eslint-plugin": "^5.4.0",
     "@typescript-eslint/parser": "^5.4.0",

+ 8 - 2
src/App.tsx

@@ -16,8 +16,14 @@ const App = defineComponent(() => {
   );
 });
 
-export function startApp(router: Router, hooks: any[] = []) {
+export function startApp(
+  router: Router,
+  hooks: any[] = [],
+  callback?: (app: ReturnType<typeof createApp>) => void
+) {
   setModuleHooks = hooks;
   queenApi.router = router;
-  createApp(App).use(router).mount("#app");
+  const app = createApp(App);
+  callback?.(app);
+  app.use(router).mount("#app");
 }

+ 65 - 0
src/modules/editor/components/CompUI/baseUI/CkEditor.tsx

@@ -0,0 +1,65 @@
+import { useEditor } from "@/modules/editor";
+import { Bold, Italic } from "@ckeditor/ckeditor5-basic-styles";
+import { InlineEditor } from "@ckeditor/ckeditor5-editor-inline";
+import { Essentials } from "@ckeditor/ckeditor5-essentials";
+import { Alignment } from "@ckeditor/ckeditor5-alignment";
+import { FontFamily, FontSize } from "@ckeditor/ckeditor5-font";
+import { Link } from "@ckeditor/ckeditor5-link";
+import { Paragraph } from "@ckeditor/ckeditor5-paragraph";
+import { defineComponent } from "vue";
+import { string } from "vue-types";
+
+export const CkEditor = defineComponent({
+  props: {
+    value: string().def("请输入文本"),
+  },
+  emits: ["change"],
+  setup(props, { emit }) {
+    const { store } = useEditor();
+    const config = {
+      plugins: [
+        Essentials,
+        Bold,
+        Italic,
+        Link,
+        Paragraph,
+        FontSize,
+        FontFamily,
+        Alignment,
+      ],
+      fontSize: {
+        options: [9, 11, 13, "default", 17, 19, 21],
+      },
+      toolbar: {
+        items: [
+          "undo",
+          "redo",
+          "|",
+          "fontFamily",
+          "fontsize",
+          "bold",
+          "italic",
+          "|",
+          "alignment",
+          "|",
+          "link",
+        ],
+      },
+    };
+    return () => (
+      <ckeditor
+        editor={InlineEditor}
+        onBlur={(e: any, editor: InlineEditor) =>
+          emit("change", editor.getData())
+        }
+        onReady={(editor: InlineEditor) => {
+          editor.setData(props.value);
+          if (!store.isEditMode) {
+            editor.enableReadOnlyMode("editor");
+          }
+        }}
+        config={config}
+      />
+    );
+  },
+});

+ 8 - 45
src/modules/editor/components/CompUI/baseUI/Text.tsx

@@ -1,58 +1,21 @@
-import { useEditor } from "@/modules/editor";
-import { css } from "@linaria/core";
-import { defineComponent, ref } from "vue";
+import { defineComponent } from "vue";
 import { string } from "vue-types";
+import { CkEditor } from "./CkEditor";
 import { View } from "./View";
 
 export const Text = defineComponent({
   props: {
-    value: string().def("请输入文本"),
+    value: string(),
   },
   emits: ["update:value"],
   setup(props, { emit }) {
-    const { store } = useEditor();
-    const textRef = ref<HTMLTextAreaElement>();
-
-    function textareaResize() {
-      const textEl = textRef.value;
-      if (textEl) {
-        textEl.style.height = "0";
-        textEl.style.height = textEl.scrollHeight + "px";
-      }
-    }
-
     return () => (
-      <View class={textStyle}>
-        {store.isEditMode ? (
-          <textarea
-            ref={textRef}
-            value={props.value}
-            rows={1}
-            onInput={(e) => {
-              emit("update:value", (e.target as HTMLInputElement).value);
-              textareaResize();
-            }}
-          />
-        ) : (
-          <div class="whitespace-pre">{props.value}</div>
-        )}
+      <View>
+        <CkEditor
+          value={props.value}
+          onChange={(v) => emit("update:value", v)}
+        />
       </View>
     );
   },
 });
-
-const textStyle = css`
-  text-align: left;
-  textarea {
-    resize: none;
-  }
-  textarea,
-  div {
-    display: block;
-    width: 100%;
-    height: 100%;
-    padding: 4px;
-    outline: none;
-    border: none;
-  }
-`;

+ 6 - 29
src/modules/editor/components/CompUI/baseUI/Textarea.tsx

@@ -1,8 +1,6 @@
-import { useEditor } from "@/modules/editor";
-import Quill from "quill";
-import "quill/dist/quill.bubble.css";
-import { defineComponent, onMounted, ref, watchEffect } from "vue";
+import { defineComponent } from "vue";
 import { string } from "vue-types";
+import { CkEditor } from "./CkEditor";
 import { View } from "./View";
 
 export const Textarea = defineComponent({
@@ -11,33 +9,12 @@ export const Textarea = defineComponent({
   },
   emits: ["update:value"],
   setup(props, { emit }) {
-    const domRef = ref();
-    const { store } = useEditor();
-    let quill: Quill | undefined = undefined;
-    onMounted(() => {
-      quill = new Quill(domRef.value, {
-        theme: "bubble",
-      });
-      store.isEditMode && quill.disable();
-      quill.on("text-change", () => {
-        emit("update:value", quill?.getContents());
-      });
-      try {
-        quill.setContents(JSON.parse(props.value));
-      } catch (error) {
-        quill.setText("初始化数据失败");
-      }
-    });
-    watchEffect(() => {
-      if (store.isEditMode) {
-        quill?.enable();
-      } else {
-        quill?.disable();
-      }
-    });
     return () => (
       <View>
-        <div class="w-1/1 h-1/1" ref={domRef}></div>
+        <CkEditor
+          value={props.value}
+          onChange={(v) => emit("update:value", v)}
+        />
       </View>
     );
   },

+ 9 - 2
src/modules/resource/actions/material.ts

@@ -4,10 +4,17 @@ import { ResourceModule } from "..";
 export const materialActions = ResourceModule.action({
   async uploadMaterial() {
     const [blob] = await queenApi.selectFile({ accept: "image/*, video/*" });
-    const res = await this.controls.uploader.uploadFile(blob, "source");
+
+    // const url = URL.createObjectURL(blob);
+    // const data = { url, size: blob.size };
+    // await this.controls.uploader.uploadBlobs(data, {
+    //   createPathKey: this.helpers.createFileName,
+    // });
+
+    const data = await this.controls.uploader.uploadFile(blob, "queenshow");
 
     const souceObj = {
-      file: res,
+      file: data,
       fileType: blob.type.split("/")[0],
       from: "upload",
     };

+ 47 - 43
src/modules/resource/components/MaterialItem.tsx

@@ -11,7 +11,7 @@ export default defineComponent({
     record: any(),
     use: string<"show" | "select">(),
   },
-  emits: ["delete", "select", "download"],
+  emits: ["delete", "select", "download", "use"],
   setup(props, { emit }) {
     return () => {
       const { active, record, use } = props;
@@ -19,47 +19,6 @@ export default defineComponent({
 
       return (
         <div class={cx(itemStyles, "relative", active && "active")}>
-          {active && (
-            <Checkbox
-              checked
-              class="!-mt-0.2em absolute top-0 left-0 text-20px text-red-200 z-3"
-            />
-          )}
-          {use == "show" && (
-            <div class="waiting absolute inset-0 z-2 flex items-center justify-center text-white hidden">
-              生成中…
-            </div>
-          )}
-          <div
-            class="absolute inset-0 flex items-center justify-center z-2 opacity-0 hover:opacity-100 transition-all text-white"
-            onClick={() => emit("select")}
-          >
-            {use == "show" && (
-              <IconDelete
-                class="icon_del absolute right-5px top-5px p-3px rounded-2px text-14px cursor-pointer"
-                onClick={() => emit("delete")}
-              />
-            )}
-            {use == "show" && (
-              <div
-                class="btn_circle rounded-1/2 text-center w-56px leading-56px cursor-pointer"
-                onClick={() => emit("download")}
-              >
-                下载
-              </div>
-            )}
-            {use == "select" && (
-              <div
-                class="btn_circle  rounded-1/2 text-center w-56px leading-56px cursor-pointer"
-                onClick={(e) => {
-                  e.stopPropagation();
-                  emit("select");
-                }}
-              >
-                使用
-              </div>
-            )}
-          </div>
           <View ratio={1.4} class="overflow-hidden">
             {record.fileType == "video" ? (
               <video src={record.file?.url} class="h-1/1 w-1/1" />
@@ -71,8 +30,53 @@ export default defineComponent({
                 }
               />
             )}
+            {active && (
+              <Checkbox
+                checked
+                class="!-mt-0.2em absolute top-0 left-0 text-20px text-red-200 z-3"
+              />
+            )}
+            {use == "show" && (
+              <div class="waiting absolute inset-0 z-2 flex items-center justify-center text-white hidden">
+                生成中…
+              </div>
+            )}
+            <div
+              class="absolute inset-0 flex items-center justify-center z-2 opacity-0 hover:opacity-100 transition-all text-white"
+              onClick={() => emit("select")}
+            >
+              {use == "show" && (
+                <IconDelete
+                  class="icon_del absolute right-5px top-5px p-3px rounded-2px text-14px cursor-pointer"
+                  onClick={() => emit("delete")}
+                />
+              )}
+              {use == "show" && (
+                <div
+                  class="btn_circle rounded-1/2 text-center w-56px leading-56px cursor-pointer"
+                  onClick={() => emit("download")}
+                >
+                  下载
+                </div>
+              )}
+              {use == "select" && (
+                <div
+                  class="btn_circle  rounded-1/2 text-center w-56px leading-56px cursor-pointer"
+                  onClick={(e) => {
+                    e.stopPropagation();
+                    emit("use");
+                  }}
+                >
+                  使用
+                </div>
+              )}
+            </div>
           </View>
-          {/* <div class="py-8px px-10px bg-dark-900">{record.name}</div> */}
+          {record.name && (
+            <div class="py-8px px-10px" style={{ backgroundColor: "#262626" }}>
+              {record.name}
+            </div>
+          )}
         </div>
       );
     };

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

@@ -0,0 +1,13 @@
+import { ResourceModule } from ".";
+
+export const helper = ResourceModule.helper({
+  createFileName(fileName: string, dir: string) {
+    const suffix = fileName.substring(fileName.lastIndexOf("."));
+    if (/[\u4e00-\u9fa5]/.test(fileName) || fileName.length > 10) {
+      fileName = `${this.controls.uploader.randomName(4)}${suffix}`;
+    }
+    return `${dir}/${Date.now()}_${this.controls.uploader.randomName(
+      6
+    )}_${fileName}`;
+  },
+});

+ 4 - 3
src/modules/resource/index.ts

@@ -3,6 +3,7 @@ import { PageListController, UploadController } from "@queenjs/controllers";
 import { ModuleRoot } from "queenjs";
 import { actions } from "./actions";
 import { compoents } from "./components";
+import { helper } from "./helper";
 import { http } from "./http";
 import { store } from "./store";
 
@@ -17,14 +18,14 @@ export class ResourceModule extends ModuleRoot {
   components = this.useComponents(compoents);
   store = this.createStore([store]);
   https = this.createHttps(http);
+  helpers = this.createHelper(helper);
 
   controls = {
     uploader: new UploadController({
       httpConfig: {
-        baseURL: "https://www.infish.cn/tree/v1/assetcenter",
+        baseURL: Dict_Apis.queentree,
       },
-      // httpConfig: () => this.config.httpConfig,
-      dir: "queentree",
+      dir: "queenshow",
     }),
     promotionListCtrl: new PageListController(this.config?.httpConfig),
     materialListCtrl: new PageListController(this.config?.httpConfig),

+ 4 - 1
src/pages/editor/index.ts

@@ -1,5 +1,8 @@
 import { startApp } from "@/App";
 import { initAuthDef } from "@/hooks/initAuthDef";
+import CKEditor from "@ckeditor/ckeditor5-vue";
 import router from "./router";
 
-startApp(router, [initAuthDef]);
+startApp(router, [initAuthDef], (app) => {
+  app.use(CKEditor);
+});

+ 7 - 4
src/pages/website/EditMaterial/components/ComponentPanel.tsx

@@ -1,3 +1,4 @@
+import { useResource } from "@/modules/resource";
 import { Image, List } from "@queenjs/ui";
 import { Button } from "ant-design-vue";
 import { defineComponent } from "vue";
@@ -5,8 +6,10 @@ import { any } from "vue-types";
 
 export default defineComponent({
   setup() {
+    const resource = useResource();
+
     return () => {
-      const list = new Array(6).fill({});
+      const list = resource.store.sourceDetail.webEditor?.matSlots || [];
       return (
         <div class="w-300px flex flex-col">
           <div class="p-15px text-16px text-white border-dark-800 border-0 border-b-1 border-solid">
@@ -14,7 +17,7 @@ export default defineComponent({
           </div>
           <List data={list} gap="10px" class="scrollbar flex-1 py-15px px-15px">
             {{
-              item: () => <CompItem record={{}} />,
+              item: (record: any) => <CompItem record={record} />,
               loadmore: () => (
                 <div class="text-center py-20px text-12px opacity-80">
                   没有更多了
@@ -40,8 +43,8 @@ const CompItem = defineComponent({
           class="flex items-center py-6px px-12px rounded-4px"
           style={{ backgroundColor: "#303030" }}
         >
-          <Image src={record.thumbnail?.url} class="w-48px rounded-4px" />
-          <div class="ml-12px flex-1">{record.name || "未命名"}</div>
+          <Image src={record.thumbnail} class="w-48px rounded-4px" />
+          <div class="ml-10px flex-1 mr-5px w-0">{record.name || "未命名"}</div>
           <Button type="primary" ghost size="small">
             替换
           </Button>

+ 9 - 4
src/pages/website/EditMaterial/components/ModelPanel.tsx

@@ -1,3 +1,4 @@
+import { useResource } from "@/modules/resource";
 import { Image, List } from "@queenjs/ui";
 import { Button } from "ant-design-vue";
 import { defineComponent } from "vue";
@@ -5,8 +6,10 @@ import { any } from "vue-types";
 
 export default defineComponent({
   setup() {
+    const resource = useResource();
+
     return () => {
-      const list = new Array(6).fill({});
+      const list = resource.store.sourceDetail.webEditor?.meshSlots || [];
       return (
         <div class="w-300px flex flex-col">
           <div class="p-15px text-16px text-white border-dark-800 border-0 border-b-1 border-solid">
@@ -14,7 +17,7 @@ export default defineComponent({
           </div>
           <List data={list} gap="10px" class="scrollbar flex-1 py-15px px-15px">
             {{
-              item: () => <ProductItem record={{}} />,
+              item: (record: any) => <ProductItem record={record} />,
               loadmore: () => (
                 <div class="text-center py-20px text-12px opacity-80">
                   没有更多了
@@ -40,8 +43,10 @@ const ProductItem = defineComponent({
           class="flex items-center py-6px px-12px rounded-4px"
           style={{ backgroundColor: "#303030" }}
         >
-          <Image src={record.thumbnail?.url} class="w-48px rounded-4px" />
-          <div class="ml-12px flex-1">{record.name || "未命名"}</div>
+          <Image src={record.thumbnail} class="w-48px rounded-4px" />
+          <div class="ml-10px flex-1 mr-5px truncate w-0">
+            {record.meshName || "未命名"}
+          </div>
           <Button type="primary" ghost size="small">
             替换
           </Button>

+ 1 - 1
src/pages/website/Material/components/MaterialTemplateModal.tsx

@@ -35,7 +35,7 @@ export default defineComponent({
               <resource.components.MaterialItem
                 use="select"
                 record={record}
-                onSelect={() => {
+                onUse={() => {
                   modal.cancel();
                   resource.actions.selectMaterial(record);
                 }}

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

@@ -27,13 +27,13 @@ export default defineComponent({
         link: "/workbench/design",
         label: "我的推广",
         icon: IconDashboard,
-        suffix: "7",
+        // suffix: "7",
       },
       {
         link: "/workstage/material",
         label: "我的素材",
         icon: IconCamera,
-        suffix: "32",
+        // suffix: "32",
       },
       {
         link: "/settings",
@@ -103,7 +103,7 @@ const rootStyles = css`
   .router-link-exact-active {
     display: block;
     border-radius: 4px;
-    background-color: #fff;
+    background-color: #414141;
     > div {
       color: @inf-text-color;
     }
@@ -165,6 +165,6 @@ const itemStyles = css`
   color: @inf-text-sub-color;
   cursor: pointer;
   &:hover {
-    background: #fff;
+    background: #414141;
   }
 `;

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

@@ -9,13 +9,13 @@ export default defineComponent({
       return (
         <Layout class={cx("!h-100vh flex", rootStyles)}>
           <Layout.Sider
-            class="scrollbar !bg-transparent overflow-y-auto"
+            class="scrollbar !bg-transparent overflow-y-auto border-dark-800 border-0 border-r-1 border-solid"
             theme="light"
             width="380px"
           >
             <LeftContent />
           </Layout.Sider>
-          <Layout.Content class="container scrollbar flex-1 my-20px mr-25px rounded-20px p-50px overflow-y-auto">
+          <Layout.Content class="page_container scrollbar flex-1 my-20px rounded-20px p-50px overflow-y-auto">
             <router-view></router-view>
           </Layout.Content>
         </Layout>
@@ -26,7 +26,7 @@ export default defineComponent({
 
 const rootStyles = css`
   background-color: @inf-layout-bg;
-  .container {
+  .page_container {
     background-color: @inf-modal-bg;
   }
 `;

+ 4 - 0
src/styles/global.less

@@ -54,3 +54,7 @@ each(@direction, {
     background: @inf-primary-hover-bg;
   }
 }
+
+.ck-powered-by {
+  display: none;
+}

+ 1 - 1
src/styles/theme.less

@@ -15,7 +15,7 @@
 @inf-border-color: #1f1f1f;
 
 @inf-mask-bg: fade(#000000, 50%);
-// @inf-modal-bg: #1f1f1f;
+@inf-modal-bg: #262626;
 
 @inf-layout-bg: #262626;
 @inf-component-bg: #262626;

+ 57 - 1
vue.config.js

@@ -2,6 +2,10 @@ const { defineConfig } = require("@vue/cli-service");
 const linariaLessLoader = require("@queenjs/webpack-loader/linaria-loader");
 const modifyVars = require("./src/styles/theme-antd");
 const path = require("path");
+const {
+  CKEditorTranslationsPlugin,
+} = require("@ckeditor/ckeditor5-dev-translations");
+const { styles } = require("@ckeditor/ckeditor5-dev-utils");
 
 // const publicPath =
 //   process.env.NODE_ENV === "production"
@@ -15,7 +19,7 @@ module.exports = defineConfig({
     editor: "src/pages/editor/index.ts",
   },
   publicPath: publicPath,
-  transpileDependencies: true,
+  transpileDependencies: [/ckeditor5-[^/\\]+[/\\]src[/\\].+\.js$/],
   devServer: {
     client: {
       overlay: {
@@ -25,6 +29,17 @@ module.exports = defineConfig({
       },
     },
   },
+  configureWebpack: {
+    plugins: [
+      // CKEditor 5 needs its own plugin to be built using webpack.
+      new CKEditorTranslationsPlugin({
+        // See https://ckeditor.com/docs/ckeditor5/latest/features/ui-language.html
+        language: "zh",
+        // Append translations to the file matching the `app` name.
+        // translationsOutputFile: /ckeditor/,
+      }),
+    ],
+  },
   chainWebpack: (config) => {
     const tsRule = config.module.rule("ts");
     tsRule
@@ -48,6 +63,47 @@ module.exports = defineConfig({
         preprocessor: linariaLessLoader("@/styles/theme"),
       })
       .before("ts-loader");
+
+    const svgRule = config.module.rule("svg");
+    // Then you can either:
+    //
+    // * clear all loaders for existing 'svg' rule:
+    //
+    //		svgRule.uses.clear();
+    //
+    // * or exclude ckeditor directory from node_modules:
+    svgRule.exclude.add(path.join(__dirname, "node_modules", "@ckeditor"));
+
+    // Add an entry for *.svg files belonging to CKEditor. You can either:
+    //
+    // * modify the existing 'svg' rule:
+    //
+    //		svgRule.use( 'raw-loader' ).loader( 'raw-loader' );
+    //
+    // * or add a new one:
+    config.module
+      .rule("cke-svg")
+      .test(/ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/)
+      .use("raw-loader")
+      .loader("raw-loader");
+
+    // (2.) Transpile the .css files imported by the editor using PostCSS.
+    // Make sure only the CSS belonging to ckeditor5-* packages is processed this way.
+    config.module
+      .rule("cke-css")
+      .test(/ckeditor5-[^/\\]+[/\\].+\.css$/)
+      .use("postcss-loader")
+      .loader("postcss-loader")
+      .tap(() => {
+        return {
+          postcssOptions: styles.getPostCssConfig({
+            themeImporter: {
+              themePath: require.resolve("@ckeditor/ckeditor5-theme-lark"),
+            },
+            minify: true,
+          }),
+        };
+      });
   },
   css: {
     loaderOptions: {

File diff suppressed because it is too large
+ 469 - 133
yarn.lock


Some files were not shown because too many files changed in this diff