Browse Source

富文本添加、上传文件、上传图片

guicheng 4 months ago
parent
commit
02e66dcc50

+ 2 - 2
.eslintrc.js

@@ -53,7 +53,7 @@ module.exports = {
     {
       files: ["*.ts", "*.vue"],
       rules: {
-        "no-undef": "off"
+        "no-undef": "on"
       }
     },
     {
@@ -117,4 +117,4 @@ module.exports = {
       }
     ]
   }
-}
+};

+ 1 - 0
package.json

@@ -101,6 +101,7 @@
     "@vitejs/plugin-vue-jsx": "^3.0.0",
     "@vue/eslint-config-prettier": "^7.0.0",
     "@vue/eslint-config-typescript": "^11.0.2",
+    "@vue/language-plugin-pug": "^2.0.21",
     "autoprefixer": "^10.4.13",
     "cloc": "^2.11.0",
     "cssnano": "^5.1.15",

+ 109 - 13
pnpm-lock.yaml

@@ -28,6 +28,7 @@ specifiers:
   '@vitejs/plugin-vue-jsx': ^3.0.0
   '@vue/eslint-config-prettier': ^7.0.0
   '@vue/eslint-config-typescript': ^11.0.2
+  '@vue/language-plugin-pug': ^2.0.21
   '@vueuse/core': ^9.13.0
   '@vueuse/motion': 2.0.0-beta.12
   '@wangeditor/editor': ^5.1.23
@@ -183,6 +184,7 @@ devDependencies:
   '@vitejs/plugin-vue-jsx': 3.0.0_vite@4.1.4+vue@3.2.47
   '@vue/eslint-config-prettier': 7.0.0_k3hr3m6agcryggk5vamhhr56wi
   '@vue/eslint-config-typescript': 11.0.2_q2d33lu7yll3f6g7gpw7pl6avm
+  '@vue/language-plugin-pug': 2.0.21
   autoprefixer: 10.4.13_postcss@8.4.21
   cloc: 2.11.0
   cssnano: 5.1.15_postcss@8.4.21
@@ -848,8 +850,8 @@ packages:
       vue-i18n:
         optional: true
     dependencies:
-      '@intlify/message-compiler': 9.3.0-beta.21
-      '@intlify/shared': 9.3.0-beta.21
+      '@intlify/message-compiler': 10.0.0-beta.1
+      '@intlify/shared': 10.0.0-beta.1
       jsonc-eslint-parser: 1.4.1
       source-map: 0.6.1
       vue-i18n: 9.2.2_vue@3.2.47
@@ -871,6 +873,14 @@ packages:
     dependencies:
       '@intlify/shared': 9.2.2
 
+  /@intlify/message-compiler/10.0.0-beta.1:
+    resolution: {integrity: sha512-rBmXBZzDgq3yPkL/3/r9uK0nrsJOYHSpaW0mtGBxxjt9pY9vaPL0UAKbVAjFPRnfEY41ixgpkpTjai6IKZ+hvg==}
+    engines: {node: '>= 16'}
+    dependencies:
+      '@intlify/shared': 10.0.0-beta.1
+      source-map-js: 1.0.2
+    dev: true
+
   /@intlify/message-compiler/9.2.2:
     resolution: {integrity: sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==}
     engines: {node: '>= 14'}
@@ -878,23 +888,15 @@ packages:
       '@intlify/shared': 9.2.2
       source-map: 0.6.1
 
-  /@intlify/message-compiler/9.3.0-beta.21:
-    resolution: {integrity: sha512-0h3D9AYKW037bfg4OArPKPYPShoWyjWco0DZBD7ASwXsQ8YlplW2HJSRW5V5hgsHpD25ghSRIpFhPPTL0A+QEw==}
+  /@intlify/shared/10.0.0-beta.1:
+    resolution: {integrity: sha512-61MnYhgqS/TyAto9CXOltHlhK2WflLBcKpIkRhZCUL2IkiVvh7qKevsqZ3RYZylyC3q19ajLW6mB+iJtnbAOpg==}
     engines: {node: '>= 16'}
-    dependencies:
-      '@intlify/shared': 9.3.0-beta.21
-      source-map-js: 1.0.2
     dev: true
 
   /@intlify/shared/9.2.2:
     resolution: {integrity: sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==}
     engines: {node: '>= 14'}
 
-  /@intlify/shared/9.3.0-beta.21:
-    resolution: {integrity: sha512-VcE3XKBlQXHKRKAGP7YB/7n0TFH4EibJSGJ+t4rZuC8gTL6r/eqYM1fsw3JJFe70wamqx1oEmd2Hu/pnPlsfiQ==}
-    engines: {node: '>= 16'}
-    dev: true
-
   /@intlify/unplugin-vue-i18n/0.8.1_vue-i18n@9.2.2:
     resolution: {integrity: sha512-BhigujPmP6JL1FSxmpogCaL+REozncHCVkJuUnefz4GWBu3X+pRe5O7PeJn8/g+Iml2ieQJz4ISPMmEbuGQjqQ==}
     engines: {node: '>= 14.16'}
@@ -911,7 +913,7 @@ packages:
         optional: true
     dependencies:
       '@intlify/bundle-utils': 3.4.0_vue-i18n@9.2.2
-      '@intlify/shared': 9.3.0-beta.21
+      '@intlify/shared': 10.0.0-beta.1
       '@rollup/pluginutils': 4.2.1
       '@vue/compiler-sfc': 3.2.45
       debug: 4.3.4
@@ -934,6 +936,15 @@ packages:
       '@intlify/core-base': 9.2.2
       '@intlify/shared': 9.2.2
 
+  /@johnsoncodehk/vscode-html-languageservice/5.2.0-34a5462:
+    resolution: {integrity: sha512-etqLfpSJ5zaw76KUNF603be6d6QsiQPmaHr9FKEp4zhLZJzWCCMH6Icak7MtLUFLZLMpL761mZNImi/joBo1ZA==}
+    dependencies:
+      '@vscode/l10n': 0.0.18
+      vscode-languageserver-textdocument: 1.0.11
+      vscode-languageserver-types: 3.17.5
+      vscode-uri: 3.0.8
+    dev: true
+
   /@jridgewell/gen-mapping/0.1.1:
     resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==}
     engines: {node: '>=6.0.0'}
@@ -1429,12 +1440,33 @@ packages:
       '@volar/source-map': 1.3.0-alpha.0
     dev: true
 
+  /@volar/language-core/2.3.0:
+    resolution: {integrity: sha512-pvhL24WUh3VDnv7Yw5N1sjhPtdx7q9g+Wl3tggmnkMcyK8GcCNElF2zHiKznryn0DiUGk+eez/p2qQhz+puuHw==}
+    dependencies:
+      '@volar/source-map': 2.3.0
+    dev: true
+
+  /@volar/language-service/2.3.0:
+    resolution: {integrity: sha512-U0ggeoHh4afYflGD2vjw8QPwnnDg5V4QDkZ5meL+B2YwrXEF9bVAHTjYaR8AxJ2qb3mwOwXLtZ9psJJSjkdctw==}
+    dependencies:
+      '@volar/language-core': 2.3.0
+      vscode-languageserver-protocol: 3.17.5
+      vscode-languageserver-textdocument: 1.0.11
+      vscode-uri: 3.0.8
+    dev: true
+
   /@volar/source-map/1.3.0-alpha.0:
     resolution: {integrity: sha512-jSdizxWFvDTvkPYZnO6ew3sBZUnS0abKCbuopkc0JrIlFbznWC/fPH3iPFIMS8/IIkRxq1Jh9VVG60SmtsdaMQ==}
     dependencies:
       muggle-string: 0.2.2
     dev: true
 
+  /@volar/source-map/2.3.0:
+    resolution: {integrity: sha512-G/228aZjAOGhDjhlyZ++nDbKrS9uk+5DMaEstjvzglaAw7nqtDyhnQAsYzUg6BMP9BtwZ59RIw5HGePrutn00Q==}
+    dependencies:
+      muggle-string: 0.4.1
+    dev: true
+
   /@volar/typescript/1.3.0-alpha.0:
     resolution: {integrity: sha512-5UItyW2cdH2mBLu4RrECRNJRgtvvzKrSCn2y3v/D61QwIDkGx4aeil6x8RFuUL5TFtV6QvVHXnsOHxNgd+sCow==}
     dependencies:
@@ -1462,6 +1494,10 @@ packages:
       '@volar/vue-language-core': 1.2.0
     dev: true
 
+  /@vscode/l10n/0.0.18:
+    resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==}
+    dev: true
+
   /@vue-macros/common/0.13.6_vue@3.2.47:
     resolution: {integrity: sha512-KXweBlWTpsWCPy3TLCRCG4mm4zsRoesZLEjxVo7KJdFYqSQBNmCBKprFkBBl36jzq96FqtZIAgQhv8se1R0vqA==}
     engines: {node: '>=14.19.0'}
@@ -1611,6 +1647,13 @@ packages:
       - supports-color
     dev: true
 
+  /@vue/language-plugin-pug/2.0.21:
+    resolution: {integrity: sha512-gvdw7U+BzGZ+4dSXTAyBcFpS37F3FeEXwu4NV0Fv5vwtQPAIAQLgd9XikcnUKsFPczQdWvo+sFor9ZKpDVYepw==}
+    dependencies:
+      '@volar/source-map': 2.3.0
+      volar-service-pug: 0.0.50
+    dev: true
+
   /@vue/reactivity-transform/3.2.45:
     resolution: {integrity: sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ==}
     dependencies:
@@ -4177,6 +4220,10 @@ packages:
     resolution: {integrity: sha512-YVE1mIJ4VpUMqZObFndk9CJu6DBJR/GB13p3tXuNbwD4XExaI5EOuRl6BHeIDxIqXZVxSfAC+y6U1Z/IxCfKUg==}
     dev: true
 
+  /muggle-string/0.4.1:
+    resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==}
+    dev: true
+
   /multimatch/4.0.0:
     resolution: {integrity: sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==}
     engines: {node: '>=8'}
@@ -5987,6 +6034,55 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: true
 
+  /volar-service-html/0.0.50_sycteybb4ku7s73ccocwznlpri:
+    resolution: {integrity: sha512-pcyQo1Pzxp5O27CIt66KjussUnKDmlTmI23L8DABOr7U7uNHV5bqzcDE8dOTHP2Jf5d0+TKAaUSWY9g5BcziQQ==}
+    peerDependencies:
+      '@volar/language-service': ~2.3.0-alpha.5
+    peerDependenciesMeta:
+      '@volar/language-service':
+        optional: true
+    dependencies:
+      '@volar/language-service': 2.3.0
+      vscode-html-languageservice: /@johnsoncodehk/vscode-html-languageservice/5.2.0-34a5462
+      vscode-languageserver-textdocument: 1.0.11
+      vscode-uri: 3.0.8
+    dev: true
+
+  /volar-service-pug/0.0.50:
+    resolution: {integrity: sha512-z9TFeHnNDhJNyQCL7KinVMpmNaPDo86odG1nG4ysn8D0uMKD/E1m7Qe5sttaKPyx8nywhQKWBYZTPsVuoIB9fQ==}
+    dependencies:
+      '@volar/language-service': 2.3.0
+      pug-lexer: 5.0.1
+      pug-parser: 6.0.0
+      volar-service-html: 0.0.50_sycteybb4ku7s73ccocwznlpri
+      vscode-html-languageservice: /@johnsoncodehk/vscode-html-languageservice/5.2.0-34a5462
+      vscode-languageserver-textdocument: 1.0.11
+    dev: true
+
+  /vscode-jsonrpc/8.2.0:
+    resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==}
+    engines: {node: '>=14.0.0'}
+    dev: true
+
+  /vscode-languageserver-protocol/3.17.5:
+    resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==}
+    dependencies:
+      vscode-jsonrpc: 8.2.0
+      vscode-languageserver-types: 3.17.5
+    dev: true
+
+  /vscode-languageserver-textdocument/1.0.11:
+    resolution: {integrity: sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==}
+    dev: true
+
+  /vscode-languageserver-types/3.17.5:
+    resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==}
+    dev: true
+
+  /vscode-uri/3.0.8:
+    resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==}
+    dev: true
+
   /vue-demi/0.13.11_vue@3.2.47:
     resolution: {integrity: sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==}
     engines: {node: '>=12'}

+ 2 - 5
src/api/user.ts

@@ -2,7 +2,7 @@
  * @Author: Gui
  * @Date: 2023-03-01 19:20:44
  * @LastEditors: guicheng 1625811865@qq.com
- * @LastEditTime: 2024-04-16 16:41:07
+ * @LastEditTime: 2024-06-20 11:35:34
  * @Description: kxs files
  * @filePath:
  */
@@ -49,10 +49,7 @@ export type RefreshTokenResult = {
 /** 登录 */
 export const getLogin = (data?: object) => {
   console.log(data);
-  return http.login(
-    "http://test.apigateway.shuangkebang.com/v1/skb/sysServer/oauth2/token",
-    data
-  );
+  return http.login(UrlList.SkbSystem.oauth2token.url, data);
 };
 /** 获取当前用户树形菜单 */
 export const getUserMenu = () => {

+ 14 - 43
src/components/Editor/index.vue

@@ -1,8 +1,8 @@
 <!--
  * @Author: Gui
  * @Date: 2023-03-01 19:20:44
- * @LastEditors: Please set LastEditors
- * @LastEditTime: 2023-06-12 10:39:51
+ * @LastEditors: guicheng 1625811865@qq.com
+ * @LastEditTime: 2024-06-20 15:03:36
  * @Description: kxs files
  * @filePath: 
 -->
@@ -12,14 +12,7 @@ import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
 import { onBeforeUnmount, ref, shallowRef, onMounted, watch } from "vue";
 import Ossupload from "@/utils/OSSupload";
 
-const props = defineProps<{
-  titleText?: string;
-  editorContent: {
-    content: "";
-    title: "";
-    type: Object;
-  };
-}>();
+const props = defineProps<{}>();
 type Res = {
   url?: string;
   describe?: string;
@@ -30,12 +23,8 @@ const editorRef = shallowRef();
 
 // 内容 HTML
 const valueHtml = ref("");
-watch(props, res => {
-  valueHtml.value = res.editorContent.content;
-  valueTitle.value = res.editorContent.title;
-});
 // 模拟异步获取内容
-onMounted(() => {});
+onMounted(() => { });
 
 const toolbarConfig: any = { excludeKeys: "fullScreen" };
 const editorConfig = {
@@ -122,10 +111,8 @@ editorConfig.MENU_CONF["uploadVideo"] = {
     });
   }
 };
-const valueTitle = ref("");
 defineExpose({
-  valueHtml,
-  valueTitle
+  valueHtml
 });
 // const buttonclick = function () {
 //   const _source = editorRef.value.getText();
@@ -145,36 +132,17 @@ defineExpose({
 <template>
   <!-- <el-button type="primary" @click="buttonclick">转文字</el-button>
   <el-button type="primary" @click="buttonclick1">转代码</el-button> -->
-  <el-input
-    v-model="valueTitle"
-    placeholder="请输入标题"
-    size="large"
-    class="mb12"
-  >
-    <template #prepend>{{
-      props.titleText ? props.titleText : "标题"
-    }}</template>
-  </el-input>
   <div class="wangeditor">
-    <Toolbar
-      style="border-bottom: 1px solid #ccc"
-      :editor="editorRef"
-      :defaultConfig="toolbarConfig"
-      :mode="mode"
-    />
-    <Editor
-      style="height: 700px; overflow-y: hidden"
-      v-model="valueHtml"
-      :defaultConfig="editorConfig"
-      :mode="mode"
-      @onCreated="handleCreated"
-    />
+    <Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
+    <Editor style="height: 700px; overflow-y: hidden" v-model="valueHtml" :defaultConfig="editorConfig" :mode="mode"
+      @onCreated="handleCreated" />
   </div>
 </template>
 <style lang="css">
 .editor-content-view p,
 .editor-content-view li {
-  white-space: pre-wrap; /* 保留空格 */
+  white-space: pre-wrap;
+  /* 保留空格 */
 }
 
 .editor-content-view blockquote {
@@ -190,7 +158,8 @@ defineExpose({
   padding: 3px;
   border-radius: 3px;
 }
-.editor-content-view pre > code {
+
+.editor-content-view pre>code {
   display: block;
   padding: 10px;
 }
@@ -198,12 +167,14 @@ defineExpose({
 .editor-content-view table {
   border-collapse: collapse;
 }
+
 .editor-content-view td,
 .editor-content-view th {
   border: 1px solid #ccc;
   min-width: 50px;
   height: 20px;
 }
+
 .editor-content-view th {
   background-color: #f1f1f1;
 }

+ 186 - 0
src/components/UploadImg/index.vue

@@ -0,0 +1,186 @@
+<!--
+ * @Author: Gui
+ * @Date: 2023-05-12 11:36:28
+ * @LastEditors: guicheng 1625811865@qq.com
+ * @LastEditTime: 2024-06-20 16:14:29
+ * @Description: kxs files
+ * @filePath: 
+-->
+<template lang="pug">
+el-upload(
+ref="uploadRef"
+v-model:file-list="fileList"
+action="http://oss.kexiaoshuang.com"
+list-type="picture-card"
+:on-change="onChange"
+:auto-upload="false"
+:on-preview="handlePictureCardPreview"
+:on-remove="handleRemove"
+:limit="props.limit"
+)
+  IconifyIconOnline( icon="material-symbols:add-rounded" width="60px" height="60px" style="margin:0 auto;color:#999")
+  template(#tip)
+    .el-upload__tip.text-red 最多上传{{props.limit}}张图片
+el-dialog( v-model="dialogVisible" title="图片预览" width="80%" draggable :destroy-on-close="true")
+  div(class="flex justify-center align-middle" )
+    img.preview(w-full :src="dialogImageUrl" alt="Preview Image" style="width:100%;height:100%;")
+
+el-dialog(v-model="clipPhoto" title="裁剪图片" :destroy-on-close="true" draggable width="30vw")
+
+  ReCropper(
+    ref="refCropper"
+    class="w-[30vw] h-[30vh]"
+    :src="selectImg"
+    :options={aspectRatio:aspectRatio}
+  )
+  template( #footer="")
+    .flex
+      el-button( @click="clipPhoto = false") 取消 
+      el-button( type="primary" @click="confirmAdd") 确定
+
+</template>
+<script lang="ts" setup>
+import { getConfig } from "@/config";
+import { ref, nextTick, onMounted, watch } from "vue";
+import Ossupload from "@/utils/OSSupload";
+import type { UploadProps, UploadUserFile } from "element-plus";
+import { ElMessage } from "element-plus";
+import ReCropper from "@/components/ReCropper";
+
+type Res = {
+  uploadurl?: string; // 上传地址
+  url?: string; // 上传地址(+域名)
+};
+const props = defineProps({
+  limit: {
+    type: Number,
+    default: 1
+  },
+  cropper: {
+    type: Boolean,
+    default: false
+  },
+  callBack: {
+    type: Function,
+    default: () => { }
+  },
+  imgList: {
+    type: Object,
+    default: []
+  },
+
+});
+onMounted(() => {
+  console.log(props.imgList, 12312)
+  if (props.imgList && props.imgList.length > 0) {
+    props.imgList.forEach(item => {
+      fileList.value.push({ name: "1", url: item });
+      UrlList.value.push(item.split(getConfig().UploadUrl + '/')[1]);
+    })
+  }
+  console.log(fileList.value, 'fileList', UrlList.value)
+})
+// watch(
+//   () => props.imgList,
+//   newValue => {
+//     console.log(newValue)
+//     if (newValue) {
+//       initImg()
+//       newValue.forEach(item => {
+//         fileList.value.push({ name: "1", url: item });
+//         UrlList.value.push(item.split(getConfig().UploadUrl + '/')[1]);
+//       })
+//     } else {
+//       initImg()
+//     }
+//     console.log(fileList.value, 'fileList', UrlList.value)
+//   }
+// );
+const aspectRatio = ref(1);
+// 文件列表
+const fileList = ref<UploadUserFile[]>([]);
+// 上传路径列表
+const UrlList = ref<UploadUserFile[]>([]);
+// 图片上传、预览、裁剪
+const dialogImageUrl = ref("");
+// 是否预览
+const dialogVisible = ref(false);
+// 是否裁剪图片
+const clipPhoto = ref(false);
+// 裁剪的图片
+const selectImg = ref("");
+// 裁剪之后的图片
+const cropperImgName = ref("");
+const uploadRef = ref();
+const refCropper = ref();
+
+const onChange = (file: any) => {
+  if (
+    file.raw.type == "image/webp" ||
+    file.raw.type == "image/png" ||
+    file.raw.type == "image/jpeg"
+  ) {
+    if (file.status == "ready") {
+      // 裁剪
+      if (props.cropper) {
+        selectImg.value = file!.url;
+        cropperImgName.value = file.name;
+        clipPhoto.value = true;
+      } else {
+        // 直接上传,不需要裁剪
+        OssUp(file.raw);
+      }
+    }
+  } else {
+    ElMessage({
+      message: "仅支持png/jpg/webp 格式的图片文件",
+      type: "error"
+    });
+  }
+  nextTick(() => {
+    uploadRef.value.clearFiles(["ready", "uploading", "fail"]);
+  });
+};
+const handlePictureCardPreview: UploadProps["onPreview"] = uploadFile => {
+  dialogImageUrl.value = uploadFile.url!;
+  dialogVisible.value = true;
+};
+const handleRemove: UploadProps["onRemove"] = (uploadFile, uploadFiles) => {
+  fileList.value = uploadFiles;
+  // console.log(uploadFiles, '--删除', uploadFile)
+  let uploadFilesdata = []
+  uploadFiles.forEach((item: any) => {
+    uploadFilesdata.push(item.url.split(getConfig().UploadUrl + '/')[1])
+  })
+  UrlList.value = uploadFilesdata
+};
+const initImg = () => {
+
+  fileList.value = []
+  UrlList.value = []
+  // fileList.value.push({ name: cropperImgName.value, url: res.url });
+  // UrlList.value.push(res.uploadurl);
+
+}
+const confirmAdd = (): void => {
+  nextTick(() => {
+    refCropper.value.cropper.getCroppedCanvas().toBlob(blob => {
+      // upload to oss
+      const file = new File([blob], cropperImgName.value, {
+        type: "image/png"
+      });
+      OssUp(file);
+    }, "image/jpeg");
+    clipPhoto.value = false;
+  });
+};
+const OssUp = file => {
+  Ossupload(file, "KxsAdmin/UploadImg").then((res: Res) => {
+    fileList.value.push({ name: cropperImgName.value, url: res.url });
+    UrlList.value.push(res.uploadurl);
+
+
+    props.callBack(UrlList.value.join(","));
+  });
+};
+</script>

+ 6 - 6
src/components/Uploadfile/index.vue

@@ -1,16 +1,16 @@
 <!--
  * @Author: Gui
  * @Date: 2023-05-12 11:36:28
- * @LastEditors: Please set LastEditors
- * @LastEditTime: 2023-06-06 14:57:14
+ * @LastEditors: guicheng 1625811865@qq.com
+ * @LastEditTime: 2024-06-20 15:36:35
  * @Description: kxs files
  * @filePath: 
 -->
 <template>
   <el-button type="primary" @click="clickupload">
     {{ btntext }}
-    <slot
-  /></el-button>
+    <slot />
+  </el-button>
   <input type="file" id="inputfile" style="display: none" />
 </template>
 <script lang="ts" setup>
@@ -31,8 +31,8 @@ onMounted(() => {
   uploaddo.value = document.querySelector("#inputfile");
   uploaddo.value.addEventListener("change", function (evt) {
     const file = evt.target.files[0];
-    Ossupload(file).then((res: Res) => {
-      props.FilePath(res.uploadurl);
+    Ossupload(file, "KxsAdmin/UploadFile").then((res: Res) => {
+      props.FilePath(res.url);
     });
   });
 });

+ 4 - 5
src/utils/OSSupload.ts

@@ -1,8 +1,8 @@
 /*
  * @Author: Gui
  * @Date: 2023-03-01 19:20:44
- * @LastEditors: Please set LastEditors
- * @LastEditTime: 2023-06-06 15:10:19
+ * @LastEditors: guicheng 1625811865@qq.com
+ * @LastEditTime: 2024-06-20 14:43:25
  * @Description: kxs files
  * @filePath:
  */
@@ -33,7 +33,7 @@ const Ossupload = function (data, Filename = "KxsAdmin/upload") {
       region: "oss-cn-chengdu",
       accessKeyId: res.data.AccessId,
       accessKeySecret: res.data.AccessKey,
-      bucket: "kexiaoshuang"
+      bucket: "kexiaoshuang-oss"
     });
     const headers = {};
     const filetype = data.name.split(".")[data.name.split(".").length - 1];
@@ -41,8 +41,7 @@ const Ossupload = function (data, Filename = "KxsAdmin/upload") {
       md5(new Date().getTime() + data.size).substring(8, 24) + "." + filetype;
     try {
       const result = await client.put(
-        `${Filename}/${filetype}/${new Date().getFullYear()}/${
-          new Date().getMonth() + 1
+        `${Filename}/${filetype}/${new Date().getFullYear()}/${new Date().getMonth() + 1
         }/${new Date().getDate()}/${filename}`,
         data,
         { headers }

+ 59 - 21
src/views/Template/template/components/add/index.vue

@@ -2,7 +2,7 @@
  * @Author: 
  * @Date: 2023-03-01 19:20:44
  * @LastEditors: guicheng 1625811865@qq.com
- * @LastEditTime: 2024-05-27 17:32:16
+ * @LastEditTime: 2024-06-20 15:58:15
  * @Description: kxs files
  * @filePath: 
 -->
@@ -14,6 +14,9 @@ export default {
 </script>
 <script setup lang="ts">
 import { inject, ref } from "vue";
+import Uploadfile from "@/components/Uploadfile/index.vue";
+import UploadImg from "@/components/UploadImg/index.vue";
+import Editor from "@/components/Editor/index.vue";
 import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 import { ElMessage, ElMessageBox } from "element-plus";
 import Upload from "@iconify-icons/ri/upload-2-fill";
@@ -22,7 +25,11 @@ import { http } from "@/utils/http";
 // 获取当前板块接口列表
 import { getGroupUrl } from "@/utils/getUrl/getUrl";
 // 获取URLLIST
-const UserUrl = await getGroupUrl(["User"]);
+async function getUerUrl() {
+  const result = await getGroupUrl(["User"]);
+  return result;
+}
+const UserUrl = getUerUrl();
 
 const props = defineProps<{
   submit: Function;
@@ -40,8 +47,13 @@ const UpdateForm = ref({
   RealName: "",
   AdminName: "",
   PassWord: "",
-  RoleId: ""
+  RoleId: "",
+  content: "",
+  upLoadFile: "",
+  upLoadImg: "",
 });
+// 富文本实例
+const childComp = ref();
 // 传参选项数据
 const optionList = [
   { Id: "1", label: "推荐" },
@@ -61,6 +73,8 @@ const transferdata = ref([
 ]);
 // 提交函数
 const submit = async () => {
+  // 富文本实例赋值
+  UpdateForm.value.content = childComp.value.valueHtml;
   const { status, info }: any = http.Request({
     url: UserUrl.User.userSearch.method,
     method: UserUrl.User.userSearch.url,
@@ -71,12 +85,13 @@ const submit = async () => {
       message: "新增成功",
       type: "success"
     });
-    UpdateForm.value = {
-      AdminName: "",
-      RealName: "",
-      RoleId: "",
-      PassWord: ""
-    };
+    UpdateForm.value.AdminName = "";
+    UpdateForm.value.RealName = "";
+    UpdateForm.value.RoleId = "";
+    UpdateForm.value.PassWord = "";
+    UpdateForm.value.content = "";
+    UpdateForm.value.upLoadFile = "";
+    UpdateForm.value.upLoadImg = "";
   } else {
     ElMessageBox.alert(info, "提示", {
       confirmButtonText: "关闭",
@@ -87,24 +102,42 @@ const submit = async () => {
 const closeFn: any = inject("closeAddVisible");
 // 关闭弹窗回调函数
 const closeVisible = () => {
-  UpdateForm.value = {
-    AdminName: "",
-    RealName: "",
-    RoleId: "",
-    PassWord: ""
-  };
+  UpdateForm.value.AdminName = "";
+  UpdateForm.value.RealName = "";
+  UpdateForm.value.RoleId = "";
+  UpdateForm.value.PassWord = "";
   closeFn();
 };
+const handleClick = () => {
+  console.log("切换选项卡");
+};
+
+//上传文件回调
+const UploadFileCallBack = (url) => {
+  ElMessage({
+    message: `文件上传成功:${url}`,
+    type: "success"
+  });
+  UpdateForm.value.upLoadFile = url;
+}
+//上传图片回调
+const UploadImgCallBack = (url) => {
+  ElMessage({
+    message: `图片上传成功:${url}`,
+    type: "success"
+  });
+  UpdateForm.value.upLoadImg = url;
+}
 </script>
 
 <template lang="pug">
 .main
-  el-dialog(v-model='props.addVisible' width="50%" title="新增" @close="closeVisible()")
+  el-dialog(v-model='props.addVisible' width="50%" title="新增" @close="closeVisible")
     //- 有选项卡模板
     el-tabs(v-model="activeId" class="demo-tabs" @tab-click="handleClick")
       el-tab-pane(label="选项卡一" name="1")
         el-form(:model='UpdateForm' label-position="right" label-width="100px")
-          el-form-item(label='账户名称' prop="RealName")
+          el-form-item(label='账户名称1' prop="RealName")
             el-input(v-model='UpdateForm.RealName' autocomplete='off' class="!w-[230px]"
               placeholder="请输入账户名称")
           el-form-item(label='用户名' prop="AdminName")
@@ -123,7 +156,7 @@ const closeVisible = () => {
               el-option(:label="item.label", :value="item.Id" v-for="(item,index) in optionList")
       el-tab-pane(label="选项卡二" name="2")
         el-form(:model='UpdateForm' label-position="right" label-width="100px")
-          el-form-item(label='账户名称' prop="RealName")
+          el-form-item(label='账户名称2' prop="RealName")
             el-input(v-model='UpdateForm.RealName' autocomplete='off' class="!w-[230px]"
               placeholder="请输入账户名称")
           el-form-item(label='用户名' prop="AdminName")
@@ -176,15 +209,20 @@ const closeVisible = () => {
         el-rate(v-model="UpdateForm.PassWord")
       el-form-item(label='穿梭框' prop="AdminName")
         el-transfer(v-model="UpdateForm.AdminName" :data="transferdata")
+      el-form-item(label='上传文件' prop="Uploadfile")
+        el-input(v-model='UpdateForm.upLoadFile' autocomplete='off' class="!w-[230px]" disabled)
+        Uploadfile(btntext="上传文件" :FilePath="UploadFileCallBack")
+      el-form-item(label='上传图片' prop="UploadImg")
+        UploadImg(:cropper="true" :callBack="UploadImgCallBack")
+      el-form-item(label='富文本' prop="childComp")
+        Editor(ref="childComp")
     el-button(
       :icon="useRenderIcon(Close)",
-      :loading="loading",
-      @click="closeVisible()"
+      @click="closeVisible"
     ) 关闭
     el-button(
       type="primary",
       :icon="useRenderIcon(Upload)",
-      :loading="loading",
       @click="submit"
     ) 确认提交
 </template>

+ 53 - 10
src/views/Template/template/components/edit/index.vue

@@ -2,7 +2,7 @@
  * @Author: 
  * @Date: 2023-03-01 19:20:44
  * @LastEditors: guicheng 1625811865@qq.com
- * @LastEditTime: 2024-05-14 14:53:14
+ * @LastEditTime: 2024-06-20 16:08:20
  * @Description: kxs files
  * @filePath: 
 -->
@@ -14,6 +14,9 @@ export default {
 </script>
 <script setup lang="ts">
 import { inject, ref } from "vue";
+import Uploadfile from "@/components/Uploadfile/index.vue";
+import UploadImg from "@/components/UploadImg/index.vue";
+import Editor from "@/components/Editor/index.vue";
 import { useRenderIcon } from "@/components/ReIcon/src/hooks";
 import { ElMessage, ElMessageBox } from "element-plus";
 import Upload from "@iconify-icons/ri/upload-2-fill";
@@ -22,7 +25,11 @@ import { http } from "@/utils/http";
 // 获取当前板块接口列表
 import { getGroupUrl } from "@/utils/getUrl/getUrl";
 // 获取URLLIST
-const UserUrl = await getGroupUrl(["User"]);
+async function getUerUrl() {
+  const result = await getGroupUrl(["User"]);
+  return result;
+}
+const UserUrl = getUerUrl();
 const props = defineProps<{
   editVisible: {
     type: Boolean;
@@ -43,7 +50,10 @@ const UpdateForm: any = ref({
   RealName: "",
   AdminName: "",
   PassWord: "",
-  RoleId: ""
+  RoleId: "",
+  content: "",
+  upLoadFile: "",
+  upLoadImg: 'https://oss.kxssaas.com/KxsAdmin/UploadImg/png/2024/6/20/00c1487f0956405e.png',
 });
 // 传参选项数据
 const optionList = [
@@ -51,10 +61,15 @@ const optionList = [
   { Id: "2", label: "实物" },
   { Id: "3", label: "虚拟商品" }
 ];
+// 富文本实例
+const childComp = ref();
 // 选项卡参数(默认值为列表某项的id)
 const activeId = ref("1");
 // 提交函数
 const submit = async () => {
+  // 富文本实例赋值
+  UpdateForm.value.content = childComp.value.valueHtml;
+  console.log(UpdateForm.value);
   const { status, info }: any = http.request(
     UserUrl.User.userSearch.method,
     UserUrl.User.userSearch.url,
@@ -65,12 +80,14 @@ const submit = async () => {
       message: "修改成功",
       type: "success"
     });
-    UpdateForm.value = {
-      AdminName: "",
-      RealName: "",
-      RoleId: "",
-      PassWord: ""
-    };
+    // 清空表单项;
+    UpdateForm.value.AdminName = "";
+    UpdateForm.value.RealName = "";
+    UpdateForm.value.RoleId = "";
+    UpdateForm.value.PassWord = "";
+    UpdateForm.value.content = "";
+    UpdateForm.value.upLoadFile = "";
+    UpdateForm.value.upLoadImg = "";
   } else {
     ElMessageBox.alert(info, "提示", {
       confirmButtonText: "关闭",
@@ -81,6 +98,8 @@ const submit = async () => {
 // 关闭弹窗回调函数
 const closeVisible = inject("closeEditVisible");
 const openVisible = async () => {
+  // 将获取到的富文本字段数据重新赋值到富文本实例
+  childComp.value.valueHtml = "<p>12312312</p>";
   //通过ID获取表格数据
   const { data, info }: any = http.Request({
     url: UserUrl.User.userSearch.method,
@@ -91,11 +110,28 @@ const openVisible = async () => {
   // 通过表格项获取数据
   UpdateForm.value = props.formData;
 };
+
+//上传文件回调
+const UploadFileCallBack = (url) => {
+  ElMessage({
+    message: `文件上传成功:${url}`,
+    type: "success"
+  });
+  UpdateForm.value.upLoadFile = url;
+}
+//上传图片回调
+const UploadImgCallBack = (url) => {
+  ElMessage({
+    message: `图片上传成功:${url}`,
+    type: "success"
+  });
+  UpdateForm.value.upLoadImg = url;
+}
 </script>
 
 <template lang="pug">
 .main
-  el-dialog(v-model='props.editVisible' width="50%" title="修改" @close="closeVisible()" @open="openVisible")
+  el-dialog(v-model='props.editVisible' width="50%" title="修改" @close="closeVisible" @open="openVisible")
     //- 有选项卡模板
     el-tabs(v-model="activeId" class="demo-tabs" @tab-click="handleClick")
       el-tab-pane(label="选项卡一" name="1")
@@ -117,6 +153,13 @@ const openVisible = async () => {
               class="!w-[230px]"
             )
               el-option(:label="item.label", :value="item.Id" v-for="(item,index) in optionList")
+          el-form-item(label='上传图片' prop="UploadImg")
+            UploadImg(:cropper="true" :callBack="UploadImgCallBack" :imgList="UpdateForm.upLoadImg.split(',')")
+          el-form-item(label='上传文件' prop="Uploadfile")
+            el-input(v-model='UpdateForm.upLoadFile' autocomplete='off' class="!w-[230px]" disabled)
+            Uploadfile(btntext="上传文件" :FilePath="UploadCallBack")
+          el-form-item(label="富文本:", prop="RoleId")
+            Editor(ref="childComp")
       el-tab-pane(label="选项卡二" name="2")
         el-form(:model='UpdateForm' label-position="right" label-width="100px")
           el-form-item(label='账户名称' prop="RealName")

+ 6 - 2
src/views/Template/template/hook.tsx

@@ -6,7 +6,11 @@ import { reactive, ref, computed, onMounted } from "vue";
 import { getGroupUrl } from "@/utils/getUrl/getUrl";
 import { http } from "@/utils/http";
 // 获取当前板块接口列表
-const UserUrl = await getGroupUrl(["User"]);
+async function getUerUrl() {
+  const result = await getGroupUrl(["User"]);
+  return result;
+}
+const UserUrl = getUerUrl();
 export function useUser() {
   // 搜索表单参数
   const form = reactive({
@@ -35,7 +39,6 @@ export function useUser() {
   ]);
   const dataList = ref([]);
   const loading = ref(false);
-  const dialogAddVisible = ref(false);
   const pagination = reactive<PaginationProps>({
     total: 0,
     pageSize: 10,
@@ -143,6 +146,7 @@ export function useUser() {
   // 新增
   const addVisible = ref(false);
   function handleAdd() {
+    console.log(123);
     addVisible.value = true;
   }
   // 修改

+ 16 - 14
src/views/Template/template/index.vue

@@ -10,13 +10,15 @@ import { useUser } from "./hook";
 import { hasAuth } from "@/router/utils";
 import { PureTableBar } from "@/components/RePureTableBar";
 import { useRenderIcon } from "@/components/ReIcon/src/hooks";
-import Add from "./components/add/index.vue"
-import Edit from "./components/edit/index.vue"
+import Add from "./components/add/index.vue";
+import Edit from "./components/edit/index.vue";
 import Search from "@iconify-icons/ep/search";
 import All from "@iconify-icons/ep/refresh-left";
 import Addicon from "@iconify-icons/ep/document-add";
 
 const formRef = ref();
+console.log(Add);
+console.log(Edit);
 const {
   form,
   loading,
@@ -33,18 +35,18 @@ const {
   addVisible,
   editVisible,
   editFormData,
-  optionList,
+  optionList
 } = useUser();
 // 关闭修改
 const closeEditVisible = () => {
-  editVisible.value = false
-}
-provide('closeEditVisible', closeEditVisible)
+  editVisible.value = false;
+};
+provide("closeEditVisible", closeEditVisible);
 // 关闭添加
 const closeAddVisible = () => {
-  addVisible.value = false
-}
-provide('closeAddVisible', closeAddVisible)
+  addVisible.value = false;
+};
+provide("closeAddVisible", closeAddVisible);
 </script>
 
 <template lang="pug">
@@ -98,7 +100,7 @@ provide('closeAddVisible', closeAddVisible)
     //- 表格组件
     PureTableBar(title="后台角色管理", @refresh="onSearch" )
       template(#buttons)
-        el-button(type="primary" :icon="useRenderIcon(Addicon)" @click="handleAdd()") 新增
+        el-button(type="primary" :icon="useRenderIcon(Addicon)" @click="handleAdd") 新增
         el-button(type="primary" :icon="useRenderIcon(Addicon)" @click="handleUpdate(row)") 编辑
       template(v-slot="{ size, checkList }")
         pure-table(stripe 
@@ -142,10 +144,10 @@ provide('closeAddVisible', closeAddVisible)
                       :icon="useRenderIcon(Delete)"
                       v-if="hasAuth(['delete'])"
                     ) 删除
-    //- Add(:addVisible="addVisible")
-    Add(:addVisible="true")
-    Edit(:editVisible="editVisible" :formData="editFormData")
-                    
+  Add(:addVisible="addVisible")
+  //- Add(:addVisible="true")
+  Edit(:editVisible="editVisible" :formData="editFormData")
+
 </template>
 
 <style scoped lang="scss">

+ 25 - 6
tsconfig.json

@@ -17,11 +17,18 @@
     "baseUrl": ".",
     "allowJs": false,
     "resolveJsonModule": true,
-    "lib": ["dom", "esnext"],
+    "lib": [
+      "dom",
+      "esnext"
+    ],
     "incremental": true,
     "paths": {
-      "@/*": ["src/*"],
-      "@build/*": ["build/*"]
+      "@/*": [
+        "src/*"
+      ],
+      "@build/*": [
+        "build/*"
+      ]
     },
     "types": [
       "node",
@@ -31,7 +38,10 @@
       "@pureadmin/descriptions/volar",
       "unplugin-vue-define-options/macros-global"
     ],
-    "typeRoots": ["./node_modules/@types/", "./types"]
+    "typeRoots": [
+      "./node_modules/@types/",
+      "./types"
+    ]
   },
   "include": [
     "mock/*.ts",
@@ -41,5 +51,14 @@
     "types/*.d.ts",
     "vite.config.ts"
   ],
-  "exclude": ["node_modules", "dist", "**/*.js"]
-}
+  "exclude": [
+    "node_modules",
+    "dist",
+    "**/*.js"
+  ],
+  "vueCompilerOptions": {
+    "plugins": [
+      "@vue/language-plugin-pug"
+    ]
+  }
+}