瀏覽代碼

移动端调整

chenrong 10 月之前
父節點
當前提交
51d7162700

+ 8 - 28
src/components/ImageUpload/index.vue

@@ -1,23 +1,10 @@
 <template>
   <div class="component-upload-image">
     <div class="upload">
-      <el-upload
-        multiple
-        :action="uploadImgUrl"
-        list-type="picture-card"
-        :on-success="handleUploadSuccess"
-        :before-upload="handleBeforeUpload"
-        :limit="limit"
-        :on-error="handleUploadError"
-        :on-exceed="handleExceed"
-        ref="imageUpload"
-        :on-remove="handleDelete"
-        :show-file-list="true"
-        :headers="headers"
-        :file-list="fileList"
-        :on-preview="handlePictureCardPreview"
-        :class="{ hide: this.fileList.length >= this.limit }"
-      >
+      <el-upload multiple :action="uploadImgUrl" list-type="picture-card" :on-success="handleUploadSuccess"
+        :before-upload="handleBeforeUpload" :limit="limit" :on-error="handleUploadError" :on-exceed="handleExceed"
+        ref="imageUpload" :on-remove="handleDelete" :show-file-list="true" :headers="headers" :file-list="fileList"
+        :on-preview="handlePictureCardPreview" :class="{ hide: this.fileList.length >= this.limit }">
         <i class="el-icon-plus"></i>
       </el-upload>
     </div>
@@ -33,16 +20,8 @@
       的文件
     </div>
 
-    <el-dialog
-      :visible.sync="dialogVisible"
-      title="预览"
-      width="800"
-      append-to-body
-    >
-      <img
-        :src="dialogImageUrl"
-        style="display: block; max-width: 100%; margin: 0 auto"
-      />
+    <el-dialog :visible.sync="dialogVisible" title="预览" width="800" append-to-body>
+      <img :src="dialogImageUrl" style="display: block; max-width: 100%; margin: 0 auto" />
     </el-dialog>
   </div>
 </template>
@@ -82,7 +61,7 @@ export default {
       dialogVisible: false,
       hideUpload: false,
       baseUrl: process.env.VUE_APP_BASE_API,
-      uploadImgUrl: process.env.VUE_APP_BASE_API + "/system/app/upload", // 上传的图片服务器地址
+      uploadImgUrl: process.env.VUE_APP_BASE_API + "/appUser/system/app/upload", // 上传的图片服务器地址
       headers: {
         UserToken: getToken(),
       },
@@ -219,6 +198,7 @@ export default {
 ::v-deep.hide .el-upload--picture-card {
   display: none;
 }
+
 // 去掉动画效果
 ::v-deep .el-list-enter-active,
 ::v-deep .el-list-leave-active {

+ 6 - 1
src/views/components/titleH5.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="h5Title">
-    <i class="el-icon-arrow-left icon"></i>
+    <i class="el-icon-arrow-left icon" @click="goBack"></i>
     <div class="name">{{ titleName }}</div>
   </div>
 </template>
@@ -13,6 +13,11 @@ export default {
       default: '标题'
     }
   },
+  methods: {
+    goBack() {
+      this.$router.go(-1)
+    }
+  }
 }
 </script>
 

+ 109 - 18
src/views/create/createH5.vue

@@ -2,16 +2,15 @@
   <div class="create bg-white" style="min-height: 100vh;">
     <TitleH5 titleName="创建角色" />
     <div class=" mx-auto">
-      <div class="container containerH5 mx-auto p-4">
-        <div class="flex flex-col gap-6">
-
-          <el-form :model="form" :rules="rules" ref="form" label-width="60px" class="form">
-            <div class="bg-gray-100 p-3 rounded-lg">
+      <div class="container containerH5 mx-auto p-4 ">
+        <div class="flex flex-col h-full w-full">
+          <el-form :model="form" :rules="rules" ref="form" label-position="top" label-width="60px" class="form">
+            <div class="bg-gray-100 p-3 rounded-lg h-full overflow-y-auto" v-show="pageNum == 1">
               <div class="text-lg font-medium">基本信息</div>
               <div class="text-xs text-black mb-2">
                 这些信息在机器人描述中供其他用户查看
               </div>
-              <div class="flex flex-col gap-4">
+              <div class="flex flex-col ">
                 <div class="flex justify-center">
                   <el-form-item label="" prop="picture" label-width="0">
                     <ImageUpload v-model="form.picture" class="imgUp" :limit="1" />
@@ -25,7 +24,7 @@
                   </div> -->
                 </div>
                 <div class="flex-1">
-                  <div class="flex flex-col gap-4 pb-4">
+                  <div class="flex flex-col pb-4">
                     <el-form-item label="名称" prop="characterName">
                       <el-input v-model="form.characterName" placeholder="填写名称"></el-input>
                     </el-form-item>
@@ -55,8 +54,22 @@
                 </div>
               </div>
             </div>
-            <div class="bg-gray-100 p-3 rounded-lg mt-2">
+            <div class="bg-gray-100 p-3 rounded-lg mt-2" v-show="pageNum == 2">
               <div class="text-gl font-medium mb-2">机器人制作</div>
+              <el-form-item label="性格" label-width="80px" prop="characterPersonalityTags" style="margin-bottom: 20px;">
+                <el-select :multiple-limit="3" v-model="form.characterPersonalityTags" multiple filterable
+                  placeholder="搜索并选择与你的机器人性格(最多三个)">
+                  <el-option :label="item.personalityName" :value="item.id" v-for="(item, index) in personalityList"
+                    :key="index"></el-option>
+                </el-select>
+              </el-form-item>
+              <el-form-item label="模型" prop="modelId" label-width="80px" style="margin-bottom: 20px;">
+                <el-radio-group class="radio" v-model="form.modelId">
+                  <el-radio-button v-for="(item, index) in modelList" :key="index" :label="item.id">
+                    {{ item.model }}
+                  </el-radio-button>
+                </el-radio-group>
+              </el-form-item>
               <el-form-item label="开场白" prop="firstContent" label-width="80px" style="margin-bottom: 20px;">
                 <el-input v-model="form.firstContent" type="textarea" :autosize="{ minRows: 4, maxRows: 4 }"
                   placeholder="帮您的机器人设计一段开场白吧"></el-input>
@@ -65,17 +78,26 @@
                 <el-input v-model="form.characterIntroduction" type="textarea" :autosize="{ minRows: 4, maxRows: 4 }"
                   placeholder="通过设置机器人的指令和反馈,机器人在玩家互动时即时回复,增强玩家的互动,有什么较好的指令。我们会对指令的使用情况进行了解,确保指令的正常使用。"></el-input>
               </el-form-item>
-              <!-- <div class="flex flex-col gap-4">
-                <div class="text-sm">描述</div>
-                <textarea
-                  class="bg-gray-600 p-2 rounded-lg text-sm w-full h-16 focus:outline-none focus:ring focus:border-blue-300"
-                  placeholder="通过设置机器人的指令和反馈,机器人在玩家互动时即时回复,增强玩家的互动,有什么较好的指令。我们会对指令的使用情况进行了解,确保指令的正常使用。"
-                ></textarea>
-              </div> -->
+              <el-form-item label="场景" prop="scene" label-width="80px" style="margin-bottom: 20px;">
+                <el-input v-model="form.scene" type="textarea" :autosize="{ minRows: 4, maxRows: 4 }"
+                  placeholder="输入您的角色所处的场景,例如:{char}和{user}现在已经交往一个月了。"></el-input>
+              </el-form-item>
+
+              <el-form-item label="对话范例" prop="dialogue" label-width="80px">
+                <el-input v-model="form.dialogue" type="textarea" :autosize="{ minRows: 4, maxRows: 4 }"
+                  :placeholder="'例如\n<START>\n{user}:嗨,我听说你喜欢在酒吧消磨时间。\n{char}:*兴奋*天呐,是的!'"></el-input>
+              </el-form-item>
             </div>
           </el-form>
-          <div class="flex justify-center">
-            <button class="bg-blue-600 text-white px-4 py-2 rounded-lg" @click.prevent="submitForm">
+          <div class="flex justify-center bottom mt-2">
+            <button class="w-full bgColor1 text-white px-4 py-2 rounded-lg" @click.prevent="next" v-show="pageNum == 1">
+              下一步
+            </button>
+            <button class="w-full px-4 py-2 rounded-lg mr-2 border" @click.prevent="previous" v-show="pageNum == 2">
+              上一步
+            </button>
+            <button v-show="pageNum == 2" class="w-full text-white px-4 py-2 rounded-lg bgColor1"
+              @click.prevent="submitForm">
               提交
             </button>
           </div>
@@ -87,7 +109,10 @@
 
 <script>
 import TitleH5 from "@/views/components/titleH5.vue"
-import { addCharacterApi } from "@/api/create.js"
+import { addCharacterApi, personalityListApi, updateCharacterApi } from "@/api/create.js"
+import {
+  getModelListApi,
+} from "@/api/chat.js"
 import { labelListApi } from "@/api/home.js"
 export default {
   components: {
@@ -95,7 +120,10 @@ export default {
   },
   data() {
     return {
+      pageNum: 1,
       labelData: [],
+      personalityList: [],
+      modelList: [],
       form: {
         characterName: "",// 人物名称
         characterIntroduction: "", //人物角色描述
@@ -137,9 +165,35 @@ export default {
   },
   mounted() {
     this.getLabelList()
+    this.getPersonalityList()
+    this.getModelList()
     // console.log(this.$route.params.searchValue, 'this.$route.params.searchValue');
   },
   methods: {
+    // 下一步
+    next() {
+      this.pageNum++
+    },
+    previous() {
+      this.pageNum--
+    },
+    getPersonalityList() {
+      let params = {
+        pageSize: 9999,
+        pageNum: 1
+      }
+      personalityListApi(params).then(res => {
+        console.log(res, '人物性格标签');
+        this.personalityList = res.rows
+      })
+    },
+    getModelList() {
+      getModelListApi().then(res => {
+        console.log(res, '模型列表');
+        this.modelList = res.data
+        this.form.modelId = this.modelList[0].id
+      })
+    },
     async addCharacter() {
       let data = {
         name: this.form.name,
@@ -171,21 +225,54 @@ export default {
               type: 'success'
             });
             this.$refs.form.resetFields()
+            this.$router.push('/profile')
           })
         }
       })
     },
   }
 }
+
 </script>
 
 <style lang="scss" scoped>
 .containerH5 {
   height: calc(100vh - 40px - 60px);
   overflow-y: auto;
+  display: flex;
+}
+
+.bottom {
+  // height: 80px;
+  margin-bottom: 20px;
 }
 </style>
 <style scoped>
+.radio>>>.el-radio-button {
+  margin-bottom: 5px;
+  margin-right: 10px;
+  /* border-left: solid 1px #DCDFE6; */
+}
+
+.radio>>>.el-radio-button__inner {
+  border-left: solid 1px #DCDFE6;
+  border-radius: 4px;
+}
+
+.radio>>>.el-radio-button__orig-radio:checked+.el-radio-button__inner {
+  border-left: solid 1px var(--bg-color1);
+  background-color: var(--bg-color1);
+  border-color: var(--bg-color1);
+  -webkit-box-shadow: -1px 0 0 0 var(--bg-color1);
+  box-shadow: -1px 0 0 0 var(--bg-color1);
+}
+
+.form {
+  flex: 1;
+  position: relative;
+  /* height: calc(100% - 60px); */
+}
+
 .form>>>.el-form-item {
   margin-bottom: 10px;
 }
@@ -199,6 +286,10 @@ export default {
   width: 100%;
 }
 
+.form>>>.el-form-item__label {
+  padding: 0 !important;
+}
+
 .form>>>.el-input__inner,
 .form>>>.el-textarea__inner,
 .form>>>.el-select__input {

+ 16 - 362
src/views/create/createScene.vue

@@ -1,378 +1,32 @@
 <template>
-  <div class=" w-full h-full app-pageContainer" style="overflow: hidden;">
-    <div class=" w-full py-3 px-10 border-b border-gray-200">
-      创建场景
-    </div>
-     <!-- 第一步场景基本信息 -->
-    <div v-show="active == 1" class="px-6 py-8 mx-auto overflow-y-auto" style="height: calc(100% - 49px - 80px); width: 1000px;">
-      <div>
-        <div class="py-4 flex flex-col">
-          <div class="w-20 h-20">
-            <div
-              v-if="!character.id"
-              @click="showPopup1 = true"
-              class="w-20 h-20 bg-gray-100 rounded-full cursor-pointer flex flex-col justify-center items-center text-sm hover:bg-gray-200">
-              <p>选择</p>
-              <p>角色</p>
-            </div>
-            <img v-else class="w-20 h-20 rounded-full cursor-pointer object-cover shadow" @click="showPopup1 = true" :src="baseApi + character.picture" alt="">
-          </div>
-          <div class="mt-1.5 text-2xl">{{character.id ? character.characterName : '请选择角色'}}</div>
-          <div class="mt-1 text-gray-400 text-sm">定义角色所属的上下文,为角色补充创作的故事或设定。</div>
-        </div>
-
-        <div class="py-4">
-          <div>场景名称</div>
-          <div class="mt-1 text-gray-400 text-sm">场景的标题</div>
-          <el-input class="mt-4" v-model="form.sceneName" placeholder="例如:第一次约会" maxlength="10" show-word-limit></el-input>
-        </div>
-
-        <div class="py-4">
-          <div>场景描述</div>
-          <div class="mt-1 text-gray-400 text-sm">
-            详细的场景描述,可以为角色补充创作的故事或设定,可以指定互动发生的位置和时间。
-          </div>
-          <el-input class="mt-4" v-model="form.sceneDescription" placeholder="例:{char} 成为 {user} 的女朋友已有一段時間了,今天你们决定开始同居。"
-            type="textarea" maxlength="400" :autosize="{ minRows: 4 }" show-word-limit></el-input>
-        </div>
-        <div class="py-4">
-          <div>欢迎语</div>
-          <div class="mt-1 text-gray-400 text-sm">
-            请填写欢迎语和指定的发言角色,這将会是进入场景时收到的第一句话,将会印象场景的剧情走向
-          </div>
-          <el-input class="mt-4" v-model="form.sceneWelcome" placeholder="例如:他的声音里充满了恼怒,问道: “你是我新來的保姆吗?”" type="textarea"
-            maxlength="400" :autosize="{ minRows: 4 }" show-word-limit></el-input>
-        </div>
-        <div class="py-4">
-          <div>模型</div>
-          <div class="flex items-start py-3">
-            <el-radio-group class="radio" v-model="form.modelId">
-              <el-radio-button v-for="(item, index) in modelList" :key="index" :label="item.id">
-                {{ item.model}}
-              </el-radio-button>
-            </el-radio-group>
-          </div>
-        </div>
-      </div>
-    </div>
-    <!-- 第二步背景 -->
-    <div v-show="active == 2" class="w-full relative" style="height: calc(100% - 49px - 80px);">
-      <img v-if="uploadList.length > 0" class=" w-full h-full object-cover" :src="baseApi + uploadList[bgActive].url" alt="">
-      <div
-        class="absolute bg-white p-4 bottom-1/2 right-1/2 transform translate-x-1/2 translate-y-1/2 rounded-lg border border-gray-200"
-        style="width: 700px; height: 582px;"
-      >
-      <el-tabs v-model="tabActive2">
-        <el-tab-pane label="上传背景" name="1">
-          <div class="flex flex-col">
-            <div>直接使用上传的图像</div>
-            <div class="mt-1 text-gray-400 text-sm">直接使用上传的图像</div>
-            <el-upload
-              class=" w-full text-center mt-4"
-              drag
-              :action="uploadUrl"
-              :headers="headers"
-              :before-upload="handleBeforeUpload"
-              :on-success="handleUploadSuccess"
-              :on-error="handleUploadError"
-              :show-file-list="false"
-              :limit="10"
-            >
-              <i class="el-icon-upload"></i>
-              <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
-              <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过5M</div>
-            </el-upload>
-            <div>背景</div>
-            <div class="mt-2 grid grid-cols-5 gap-y-2">
-              <div v-for="(item, index) in uploadList" :key="index" @click="bgActive = index">
-                <img class=" rounded object-cover cursor-pointer" :class="bgActive === index ? 'bgActive' : ''" style="width: 120px; height: 90px;" :src="baseApi + item.url" alt="">
-              </div>
-            </div>
-          </div>
-        </el-tab-pane>
-      </el-tabs>
-      </div>
-    </div>
-    <div class="bottom flex justify-end items-center pr-6">
-      <el-button v-if="active == 1" type="primary" :disabled="nextDisabled" @click="next()">下一步</el-button>
-      <el-button v-if="active == 2" @click="active--">上一步</el-button>
-
-      <el-dropdown @command="handleCommand" trigger="click">
-        <el-button class="mx-2 w-28 " v-show="active == 2">
-          {{ this.form.type == 0?'公开':'非公开' }}
-          <i class="el-icon-arrow-up el-icon--right"></i>
-        </el-button>
-        <el-dropdown-menu slot="dropdown">
-          <el-dropdown-item command="0">公开</el-dropdown-item>
-          <el-dropdown-item command="1">非公开</el-dropdown-item>
-        </el-dropdown-menu>
-      </el-dropdown>
-      <el-button v-if="active == 2" :disabled="uploadList.length == 0" type="primary" @click="submit">发布</el-button>
-    </div>
-    <!-- 选择角色对话框 -->
-    <el-dialog
-      class="dialog"
-      title="选择角色"
-      :visible.sync="showPopup1"
-      width="600"
-    >
-      <div>
-        <span>选择要在哪个角色上新增场景?</span>
-        <el-tabs v-model="tabActive" @tab-click="handleClickTab">
-          <el-tab-pane label="我的角色" name="1">
-            <div class=" grid grid-cols-5 gap-8">
-              <div v-for="(item, index) in userCharacterList" :key="index" @click="selectCharacter(item)">
-                <img class="rounded-full object-cover cursor-pointer w-20 h-20" :src="baseApi + item.picture" alt="">
-                <div class="characterName text-center w-20">{{ item.characterName }}</div>
-              </div>
-            </div>
-          </el-tab-pane>
-          <el-tab-pane label="热门角色" name="2">
-            <div class=" grid grid-cols-5 gap-8 justify-items-center">
-              <div v-for="(item, index) in characterList" :key="index" @click="selectCharacter(item)">
-                <img class="rounded-full object-cover cursor-pointer w-20 h-20" :src="baseApi + item.picture" alt="">
-                <div class="characterName text-center w-20">{{ item.characterName }}</div>
-              </div>
-            </div>
-          </el-tab-pane>
-        </el-tabs>
-      </div>
-
-    </el-dialog>
+  <div class="app-pageContainer">
+    <CreateScenePC v-if="!$store.state.app.isMobile" />
+    <CreateSceneH5 v-else />
   </div>
 </template>
 
 <script>
-import { getToken } from "@/utils/auth";
-import {
-  getModelListApi,
-} from "@/api/chat.js"
-import { characterListApi } from "@/api/home.js"
-import { addSceneApi, getSceneDetailApi, editSceneApi } from "@/api/create.js"
-import { detailApi } from "@/api/detail.js"
-import { queryCharactersApi } from "@/api/profile.js"
+import CreateScenePC from "./createScenePC.vue"
+import CreateSceneH5 from "./createSceneH5.vue"
+
 export default {
+  name: "create",
+  components: {
+    CreateScenePC,
+    CreateSceneH5
+  },
   data() {
     return {
-      active: 1,
-      showPopup1: false,
-      tabActive: '1',
-      tabActive2: '1',
-      form: {
-        // 角色id
-        characterId: '',
-        // 场景名称
-        sceneName: '',
-        // 场景描述
-        sceneDescription: '',
-        // 欢迎语
-        sceneWelcome: '',
-        // 模型
-        modelId: '',
-        // 背景图
-        background: '',
-        //公开非公开
-        type: 0
-      },
-      // 模型列表
-      modelList: [],
-      bagImg: '',
-      // 用户创建的角色列表
-      userCharacterList: [],
-      // 热门角色列表
-      characterList: [],
-      // 选中的角色对象
-      character: {},
-      // 上传图片相关↓
-      uploadUrl: process.env.VUE_APP_BASE_API + "/system/app/upload", // 上传的图片服务器地址
-      headers: {
-        UserToken: getToken()
-      },
-      uploadList: [],
-      fileSize: 5,
-      bgActive: 0
+
     }
   },
   mounted() {
-    // 查询用户自己创建的角色
-    this.queryCharacters()
-    this.getModelList()
-    this.getCharacterList()
-    if (this.$route.query.characterId) {
-      this.getDetail(this.$route.query.characterId)
-      // this.character = {
-      //   id: this.$route.query.characterId,
-      // }
-      this.form.characterId = this.$route.query.characterId
-    }
-    if (this.$route.query.sceneId) {
-      this.getSceneDetai(this.$route.query.sceneId)
-    }
-  },
-  computed: {
-    nextDisabled() {
-      return this.form.sceneName == '' || this.form.sceneDescription == '' || this.form.sceneWelcome == '' || this.form.modelId == ''
-    }
+
   },
   methods: {
-    queryCharacters() {
-      let params = {
-        pageSize: 10,
-        pageNum: 1
-      }
-      queryCharactersApi(params).then(res => {
-        console.log(res, '人物列表');
-        this.userCharacterList = res.rows
-      })
-    },
-    getCharacterList(query) {
-      let params = {
-        pageSize: 10,
-        pageNum: 1
-      }
-      if (query) {
-        params = {...params, ...query}
-      }
-      characterListApi(params).then(res => {
-        // console.log(res, '角色列表');
-        this.characterList = res.rows
-      })
-    },
-    getModelList() {
-      getModelListApi().then(res => {
-        console.log(res, '模型列表');
-        this.modelList = res.data
-      })
-    },
-    // 获取角色详情
-    getDetail(id) {
-      detailApi(id).then(res => {
-        console.log(res, '角色详情');
-        this.character = res.data
-      })
-    },
-    // 获取场景详情
-    getSceneDetai(id) {
-      getSceneDetailApi(id).then(res => {
-        console.log(res, '场景详情');
-        this.form = res.data
-        let backgroundArr = res.data.background.split('/')
-        this.uploadList.push({ name: backgroundArr[backgroundArr.length - 1], url: res.data.background });
-      })
-    },
-    // 选择角色
-    selectCharacter(value) {
-      console.log(value, 'value');
-      this.character = value
-      this.form.characterId = value.id
-      this.showPopup1 = false
-    },
-    handleCommand(value) {
-      this.form.type = value
-    },
-    // 下一步
-    next() {
-      this.active++
-    },
-    submit() {
-      this.form.background = this.uploadList[this.bgActive].url
-      if (this.form.sceneId) {
-        // 修改
-        editSceneApi(this.form).then(res => {
-          console.log(res, 'res>>>>>');
-          this.$message({
-            type: 'success',
-            message: '修改成功!'
-          });
-          this.$router.push('/profile')
-        })
-      } else {
-        // 新增
-        addSceneApi(this.form).then(res => {
-          console.log(res, 'res>>>>>');
-          this.$message({
-            type: 'success',
-            message: '发布成功!'
-          });
-          this.$router.push('/profile')
-        })
-      }
-    },
-    handleClickTab(tab, event) {
 
-    },
-    // 上传背景相关业务
-    // 上传前校检格式和大小
-    handleBeforeUpload(file) {
-      // 校检文件大小
-      if (this.fileSize) {
-        const isLt = file.size / 1024 / 1024 < this.fileSize;
-        if (!isLt) {
-          this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`);
-          return false;
-        }
-      }
-      return true;
-    },
-    // 上传成功回调
-    handleUploadSuccess(res, file) {
-      if (res.code === 200) {
-        this.uploadList.push({ name: res.originalFilename, url: res.fileName });
-        this.$message({
-          type: 'success',
-          message: '上传成功!'
-        });
-      } else {
-        this.$message({
-          type: 'error',
-          message: res.msg
-        });
-      }
-    },
-    // 上传结束处理
-    uploadedSuccessfully() {
-      console.log(this.uploadList, 'this.uploadList');
-      // this.$emit("input", this.listToString(this.fileList));
-      // this.$modal.closeLoading();
-    },
-    // 上传失败
-    handleUploadError() {
-      this.$modal.msgError("上传图片失败,请重试");
-    },
-  }
-}
+  },
+};
 </script>
 
-<style lang="scss" scoped>
-.bottom {
-  height: 80px;
-}
-.characterName {
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
-.bgActive {
-  border: solid 2px var(--bg-color1);
-}
-</style>
-<style scoped>
-.radio>>>.el-radio-button {
-  margin-bottom: 5px;
-  margin-right: 10px;
-  /* border-left: solid 1px #DCDFE6; */
-}
-
-.radio>>>.el-radio-button__inner {
-  border-left: solid 1px #DCDFE6;
-  border-radius: 4px;
-}
-
-.radio>>>.el-radio-button__orig-radio:checked+.el-radio-button__inner {
-  border-left: solid 1px var(--bg-color1);
-  background-color: var(--bg-color1);
-  border-color: var(--bg-color1);
-  -webkit-box-shadow: -1px 0 0 0 var(--bg-color1);
-  box-shadow: -1px 0 0 0 var(--bg-color1);
-}
-</style>
+<style scoped lang="scss"></style>

+ 369 - 0
src/views/create/createSceneH5.vue

@@ -0,0 +1,369 @@
+<template>
+  <div class=" w-full h-full app-pageContainer" style="overflow: hidden;">
+    <div class=" w-full py-3 px-10 border-b border-gray-200">
+      创建场景
+    </div>
+    <!-- 第一步场景基本信息 -->
+    <div v-show="active == 1" class="px-6 py-8 mx-auto overflow-y-auto w-full"
+      style="height: calc(100% - 49px - 80px - 60px);">
+      <div>
+        <div class="py-4 flex flex-col">
+          <div class="w-20 h-20">
+            <div v-if="!character.id" @click="showPopup1 = true"
+              class="w-20 h-20 bg-gray-100 rounded-full cursor-pointer flex flex-col justify-center items-center text-sm hover:bg-gray-200">
+              <p>选择</p>
+              <p>角色</p>
+            </div>
+            <img v-else class="w-20 h-20 rounded-full cursor-pointer object-cover shadow" @click="showPopup1 = true"
+              :src="baseApi + character.picture" alt="">
+          </div>
+          <div class="mt-1.5 text-2xl">{{ character.id ? character.characterName : '请选择角色' }}</div>
+          <div class="mt-1 text-gray-400 text-sm">定义角色所属的上下文,为角色补充创作的故事或设定。</div>
+        </div>
+
+        <div class="py-4">
+          <div>场景名称</div>
+          <div class="mt-1 text-gray-400 text-sm">场景的标题</div>
+          <el-input class="mt-4" v-model="form.sceneName" placeholder="例如:第一次约会" maxlength="10"
+            show-word-limit></el-input>
+        </div>
+
+        <div class="py-4">
+          <div>场景描述</div>
+          <div class="mt-1 text-gray-400 text-sm">
+            详细的场景描述,可以为角色补充创作的故事或设定,可以指定互动发生的位置和时间。
+          </div>
+          <el-input class="mt-4" v-model="form.sceneDescription" placeholder="例:{char} 成为 {user} 的女朋友已有一段時間了,今天你们决定开始同居。"
+            type="textarea" maxlength="400" :autosize="{ minRows: 4 }" show-word-limit></el-input>
+        </div>
+        <div class="py-4">
+          <div>欢迎语</div>
+          <div class="mt-1 text-gray-400 text-sm">
+            请填写欢迎语和指定的发言角色,這将会是进入场景时收到的第一句话,将会印象场景的剧情走向
+          </div>
+          <el-input class="mt-4" v-model="form.sceneWelcome" placeholder="例如:他的声音里充满了恼怒,问道: “你是我新來的保姆吗?”" type="textarea"
+            maxlength="400" :autosize="{ minRows: 4 }" show-word-limit></el-input>
+        </div>
+        <div class="py-4">
+          <div>模型</div>
+          <div class="flex items-start py-3">
+            <el-radio-group class="radio" v-model="form.modelId">
+              <el-radio-button v-for="(item, index) in modelList" :key="index" :label="item.id">
+                {{ item.model }}
+              </el-radio-button>
+            </el-radio-group>
+          </div>
+        </div>
+      </div>
+    </div>
+    <!-- 第二步背景 -->
+    <div v-show="active == 2" class="w-full relative" style="height: calc(100% - 49px - 80px - 60px);">
+      <img v-if="uploadList.length > 0" class=" w-full h-full object-cover" :src="baseApi + uploadList[bgActive].url"
+        alt="">
+      <div
+        class="absolute bg-white p-4 bottom-1/2 right-1/2 transform translate-x-1/2 translate-y-1/2 rounded-lg border border-gray-200"
+        style="height: 582px;">
+        <el-tabs v-model="tabActive2">
+          <el-tab-pane label="上传背景" name="1">
+            <div class="flex flex-col">
+              <div>直接使用上传的图像</div>
+              <div class="mt-1 text-gray-400 text-sm">直接使用上传的图像</div>
+              <el-upload class=" w-full text-center mt-4" drag :action="uploadUrl" :headers="headers"
+                :before-upload="handleBeforeUpload" :on-success="handleUploadSuccess" :on-error="handleUploadError"
+                :show-file-list="false" :limit="10">
+                <i class="el-icon-upload"></i>
+                <div class="el-upload__text"><em>点击上传</em></div>
+                <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过5M</div>
+              </el-upload>
+              <div>背景</div>
+              <div class="mt-2 grid grid-cols-4 gap-1 gap-y-2">
+                <div v-for="(item, index) in uploadList" :key="index" @click="bgActive = index">
+                  <img class=" rounded object-cover cursor-pointer border" :class="bgActive === index ? 'bgActive' : ''"
+                    style="width: 120px; height: 90px;" :src="baseApi + item.url" alt="">
+                </div>
+              </div>
+            </div>
+          </el-tab-pane>
+        </el-tabs>
+      </div>
+    </div>
+    <div class="bottom flex justify-end items-center pr-6">
+      <el-button v-if="active == 1" type="primary" :disabled="nextDisabled" @click="next()">下一步</el-button>
+      <el-button v-if="active == 2" @click="active--">上一步</el-button>
+
+      <el-dropdown @command="handleCommand" trigger="click">
+        <el-button class="mx-2 w-28 " v-show="active == 2">
+          {{ this.form.type == 0 ? '公开' : '非公开' }}
+          <i class="el-icon-arrow-up el-icon--right"></i>
+        </el-button>
+        <el-dropdown-menu slot="dropdown">
+          <el-dropdown-item command="0">公开</el-dropdown-item>
+          <el-dropdown-item command="1">非公开</el-dropdown-item>
+        </el-dropdown-menu>
+      </el-dropdown>
+      <el-button v-if="active == 2" :disabled="uploadList.length == 0" type="primary" @click="submit">发布</el-button>
+    </div>
+    <!-- 选择角色对话框 -->
+    <el-dialog class="dialog" title="选择角色" :visible.sync="showPopup1" fullscreen>
+      <div>
+        <span>选择要在哪个角色上新增场景?</span>
+        <el-tabs v-model="tabActive" @tab-click="handleClickTab">
+          <el-tab-pane label="我的角色" name="1">
+            <div class=" grid grid-cols-3 gap-8">
+              <div v-for="(item, index) in userCharacterList" :key="index" @click="selectCharacter(item)">
+                <img class="rounded-full object-cover cursor-pointer w-20 h-20" :src="baseApi + item.picture" alt="">
+                <div class="characterName text-center w-20">{{ item.characterName }}</div>
+              </div>
+            </div>
+          </el-tab-pane>
+          <el-tab-pane label="热门角色" name="2">
+            <div class=" grid grid-cols-3 gap-8 justify-items-center">
+              <div v-for="(item, index) in characterList" :key="index" @click="selectCharacter(item)">
+                <img class="rounded-full object-cover cursor-pointer w-20 h-20" :src="baseApi + item.picture" alt="">
+                <div class="characterName text-center w-20">{{ item.characterName }}</div>
+              </div>
+            </div>
+          </el-tab-pane>
+        </el-tabs>
+      </div>
+
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth";
+import {
+  getModelListApi,
+} from "@/api/chat.js"
+import { characterListApi } from "@/api/home.js"
+import { addSceneApi, getSceneDetailApi, editSceneApi } from "@/api/create.js"
+import { detailApi } from "@/api/detail.js"
+import { queryCharactersApi } from "@/api/profile.js"
+export default {
+  data() {
+    return {
+      active: 1,
+      showPopup1: false,
+      tabActive: '1',
+      tabActive2: '1',
+      form: {
+        // 角色id
+        characterId: '',
+        // 场景名称
+        sceneName: '',
+        // 场景描述
+        sceneDescription: '',
+        // 欢迎语
+        sceneWelcome: '',
+        // 模型
+        modelId: '',
+        // 背景图
+        background: '',
+        //公开非公开
+        type: 0
+      },
+      // 模型列表
+      modelList: [],
+      bagImg: '',
+      // 用户创建的角色列表
+      userCharacterList: [],
+      // 热门角色列表
+      characterList: [],
+      // 选中的角色对象
+      character: {},
+      // 上传图片相关↓
+      uploadUrl: process.env.VUE_APP_BASE_API + "/appUser/system/app/upload", // 上传的图片服务器地址
+      headers: {
+        UserToken: getToken()
+      },
+      uploadList: [],
+      fileSize: 5,
+      bgActive: 0
+    }
+  },
+  mounted() {
+    // 查询用户自己创建的角色
+    this.queryCharacters()
+    this.getModelList()
+    this.getCharacterList()
+    if (this.$route.query.characterId) {
+      this.getDetail(this.$route.query.characterId)
+      // this.character = {
+      //   id: this.$route.query.characterId,
+      // }
+      this.form.characterId = this.$route.query.characterId
+    }
+    if (this.$route.query.sceneId) {
+      this.getSceneDetai(this.$route.query.sceneId)
+    }
+  },
+  computed: {
+    nextDisabled() {
+      return this.form.sceneName == '' || this.form.sceneDescription == '' || this.form.sceneWelcome == '' || this.form.modelId == ''
+    }
+  },
+  methods: {
+    queryCharacters() {
+      let params = {
+        pageSize: 10,
+        pageNum: 1
+      }
+      queryCharactersApi(params).then(res => {
+        console.log(res, '人物列表');
+        this.userCharacterList = res.rows
+      })
+    },
+    getCharacterList(query) {
+      let params = {
+        pageSize: 10,
+        pageNum: 1
+      }
+      if (query) {
+        params = { ...params, ...query }
+      }
+      characterListApi(params).then(res => {
+        // console.log(res, '角色列表');
+        this.characterList = res.rows
+      })
+    },
+    getModelList() {
+      getModelListApi().then(res => {
+        console.log(res, '模型列表');
+        this.modelList = res.data
+      })
+    },
+    // 获取角色详情
+    getDetail(id) {
+      detailApi(id).then(res => {
+        console.log(res, '角色详情');
+        this.character = res.data
+      })
+    },
+    // 获取场景详情
+    getSceneDetai(id) {
+      getSceneDetailApi(id).then(res => {
+        console.log(res, '场景详情');
+        this.form = res.data
+        let backgroundArr = res.data.background.split('/')
+        this.uploadList.push({ name: backgroundArr[backgroundArr.length - 1], url: res.data.background });
+      })
+    },
+    // 选择角色
+    selectCharacter(value) {
+      console.log(value, 'value');
+      this.character = value
+      this.form.characterId = value.id
+      this.showPopup1 = false
+    },
+    handleCommand(value) {
+      this.form.type = value
+    },
+    // 下一步
+    next() {
+      this.active++
+    },
+    submit() {
+      this.form.background = this.uploadList[this.bgActive].url
+      if (this.form.sceneId) {
+        // 修改
+        editSceneApi(this.form).then(res => {
+          console.log(res, 'res>>>>>');
+          this.$message({
+            type: 'success',
+            message: '修改成功!'
+          });
+          this.$router.push('/profile')
+        })
+      } else {
+        // 新增
+        addSceneApi(this.form).then(res => {
+          console.log(res, 'res>>>>>');
+          this.$message({
+            type: 'success',
+            message: '发布成功!'
+          });
+          this.$router.push('/profile')
+        })
+      }
+    },
+    handleClickTab(tab, event) {
+
+    },
+    // 上传背景相关业务
+    // 上传前校检格式和大小
+    handleBeforeUpload(file) {
+      // 校检文件大小
+      if (this.fileSize) {
+        const isLt = file.size / 1024 / 1024 < this.fileSize;
+        if (!isLt) {
+          this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`);
+          return false;
+        }
+      }
+      return true;
+    },
+    // 上传成功回调
+    handleUploadSuccess(res, file) {
+      if (res.code === 200) {
+        this.uploadList.push({ name: res.originalFilename, url: res.fileName });
+        this.$message({
+          type: 'success',
+          message: '上传成功!'
+        });
+      } else {
+        this.$message({
+          type: 'error',
+          message: res.msg
+        });
+      }
+    },
+    // 上传结束处理
+    uploadedSuccessfully() {
+      console.log(this.uploadList, 'this.uploadList');
+      // this.$emit("input", this.listToString(this.fileList));
+      // this.$modal.closeLoading();
+    },
+    // 上传失败
+    handleUploadError() {
+      this.$modal.msgError("上传图片失败,请重试");
+    },
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.bottom {
+  height: 80px;
+}
+
+.characterName {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.bgActive {
+  border: solid 2px var(--bg-color1);
+}
+</style>
+<style scoped>
+.radio>>>.el-radio-button {
+  margin-bottom: 5px;
+  margin-right: 10px;
+  /* border-left: solid 1px #DCDFE6; */
+}
+
+.radio>>>.el-radio-button__inner {
+  border-left: solid 1px #DCDFE6;
+  border-radius: 4px;
+}
+
+.radio>>>.el-radio-button__orig-radio:checked+.el-radio-button__inner {
+  border-left: solid 1px var(--bg-color1);
+  background-color: var(--bg-color1);
+  border-color: var(--bg-color1);
+  -webkit-box-shadow: -1px 0 0 0 var(--bg-color1);
+  box-shadow: -1px 0 0 0 var(--bg-color1);
+}
+</style>

+ 369 - 0
src/views/create/createScenePC.vue

@@ -0,0 +1,369 @@
+<template>
+  <div class=" w-full h-full app-pageContainer" style="overflow: hidden;">
+    <div class=" w-full py-3 px-10 border-b border-gray-200">
+      创建场景
+    </div>
+    <!-- 第一步场景基本信息 -->
+    <div v-show="active == 1" class="px-6 py-8 mx-auto overflow-y-auto"
+      style="height: calc(100% - 49px - 80px); width: 1000px;">
+      <div>
+        <div class="py-4 flex flex-col">
+          <div class="w-20 h-20">
+            <div v-if="!character.id" @click="showPopup1 = true"
+              class="w-20 h-20 bg-gray-100 rounded-full cursor-pointer flex flex-col justify-center items-center text-sm hover:bg-gray-200">
+              <p>选择</p>
+              <p>角色</p>
+            </div>
+            <img v-else class="w-20 h-20 rounded-full cursor-pointer object-cover shadow" @click="showPopup1 = true"
+              :src="baseApi + character.picture" alt="">
+          </div>
+          <div class="mt-1.5 text-2xl">{{ character.id ? character.characterName : '请选择角色' }}</div>
+          <div class="mt-1 text-gray-400 text-sm">定义角色所属的上下文,为角色补充创作的故事或设定。</div>
+        </div>
+
+        <div class="py-4">
+          <div>场景名称</div>
+          <div class="mt-1 text-gray-400 text-sm">场景的标题</div>
+          <el-input class="mt-4" v-model="form.sceneName" placeholder="例如:第一次约会" maxlength="10"
+            show-word-limit></el-input>
+        </div>
+
+        <div class="py-4">
+          <div>场景描述</div>
+          <div class="mt-1 text-gray-400 text-sm">
+            详细的场景描述,可以为角色补充创作的故事或设定,可以指定互动发生的位置和时间。
+          </div>
+          <el-input class="mt-4" v-model="form.sceneDescription" placeholder="例:{char} 成为 {user} 的女朋友已有一段時間了,今天你们决定开始同居。"
+            type="textarea" maxlength="400" :autosize="{ minRows: 4 }" show-word-limit></el-input>
+        </div>
+        <div class="py-4">
+          <div>欢迎语</div>
+          <div class="mt-1 text-gray-400 text-sm">
+            请填写欢迎语和指定的发言角色,這将会是进入场景时收到的第一句话,将会印象场景的剧情走向
+          </div>
+          <el-input class="mt-4" v-model="form.sceneWelcome" placeholder="例如:他的声音里充满了恼怒,问道: “你是我新來的保姆吗?”" type="textarea"
+            maxlength="400" :autosize="{ minRows: 4 }" show-word-limit></el-input>
+        </div>
+        <div class="py-4">
+          <div>模型</div>
+          <div class="flex items-start py-3">
+            <el-radio-group class="radio" v-model="form.modelId">
+              <el-radio-button v-for="(item, index) in modelList" :key="index" :label="item.id">
+                {{ item.model }}
+              </el-radio-button>
+            </el-radio-group>
+          </div>
+        </div>
+      </div>
+    </div>
+    <!-- 第二步背景 -->
+    <div v-show="active == 2" class="w-full relative" style="height: calc(100% - 49px - 80px);">
+      <img v-if="uploadList.length > 0" class=" w-full h-full object-cover" :src="baseApi + uploadList[bgActive].url"
+        alt="">
+      <div
+        class="absolute bg-white p-4 bottom-1/2 right-1/2 transform translate-x-1/2 translate-y-1/2 rounded-lg border border-gray-200"
+        style="width: 700px; height: 582px;">
+        <el-tabs v-model="tabActive2">
+          <el-tab-pane label="上传背景" name="1">
+            <div class="flex flex-col">
+              <div>直接使用上传的图像</div>
+              <div class="mt-1 text-gray-400 text-sm">直接使用上传的图像</div>
+              <el-upload class=" w-full text-center mt-4" drag :action="uploadUrl" :headers="headers"
+                :before-upload="handleBeforeUpload" :on-success="handleUploadSuccess" :on-error="handleUploadError"
+                :show-file-list="false" :limit="10">
+                <i class="el-icon-upload"></i>
+                <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
+                <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过5M</div>
+              </el-upload>
+              <div>背景</div>
+              <div class="mt-2 grid grid-cols-5 gap-y-2">
+                <div v-for="(item, index) in uploadList" :key="index" @click="bgActive = index">
+                  <img class=" rounded object-cover cursor-pointer" :class="bgActive === index ? 'bgActive' : ''"
+                    style="width: 120px; height: 90px;" :src="baseApi + item.url" alt="">
+                </div>
+              </div>
+            </div>
+          </el-tab-pane>
+        </el-tabs>
+      </div>
+    </div>
+    <div class="bottom flex justify-end items-center pr-6">
+      <el-button v-if="active == 1" type="primary" :disabled="nextDisabled" @click="next()">下一步</el-button>
+      <el-button v-if="active == 2" @click="active--">上一步</el-button>
+
+      <el-dropdown @command="handleCommand" trigger="click">
+        <el-button class="mx-2 w-28 " v-show="active == 2">
+          {{ this.form.type == 0 ? '公开' : '非公开' }}
+          <i class="el-icon-arrow-up el-icon--right"></i>
+        </el-button>
+        <el-dropdown-menu slot="dropdown">
+          <el-dropdown-item command="0">公开</el-dropdown-item>
+          <el-dropdown-item command="1">非公开</el-dropdown-item>
+        </el-dropdown-menu>
+      </el-dropdown>
+      <el-button v-if="active == 2" :disabled="uploadList.length == 0" type="primary" @click="submit">发布</el-button>
+    </div>
+    <!-- 选择角色对话框 -->
+    <el-dialog class="dialog" title="选择角色" :visible.sync="showPopup1" width="600">
+      <div>
+        <span>选择要在哪个角色上新增场景?</span>
+        <el-tabs v-model="tabActive" @tab-click="handleClickTab">
+          <el-tab-pane label="我的角色" name="1">
+            <div class=" grid grid-cols-5 gap-8">
+              <div v-for="(item, index) in userCharacterList" :key="index" @click="selectCharacter(item)">
+                <img class="rounded-full object-cover cursor-pointer w-20 h-20" :src="baseApi + item.picture" alt="">
+                <div class="characterName text-center w-20">{{ item.characterName }}</div>
+              </div>
+            </div>
+          </el-tab-pane>
+          <el-tab-pane label="热门角色" name="2">
+            <div class=" grid grid-cols-5 gap-8 justify-items-center">
+              <div v-for="(item, index) in characterList" :key="index" @click="selectCharacter(item)">
+                <img class="rounded-full object-cover cursor-pointer w-20 h-20" :src="baseApi + item.picture" alt="">
+                <div class="characterName text-center w-20">{{ item.characterName }}</div>
+              </div>
+            </div>
+          </el-tab-pane>
+        </el-tabs>
+      </div>
+
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth";
+import {
+  getModelListApi,
+} from "@/api/chat.js"
+import { characterListApi } from "@/api/home.js"
+import { addSceneApi, getSceneDetailApi, editSceneApi } from "@/api/create.js"
+import { detailApi } from "@/api/detail.js"
+import { queryCharactersApi } from "@/api/profile.js"
+export default {
+  data() {
+    return {
+      active: 1,
+      showPopup1: false,
+      tabActive: '1',
+      tabActive2: '1',
+      form: {
+        // 角色id
+        characterId: '',
+        // 场景名称
+        sceneName: '',
+        // 场景描述
+        sceneDescription: '',
+        // 欢迎语
+        sceneWelcome: '',
+        // 模型
+        modelId: '',
+        // 背景图
+        background: '',
+        //公开非公开
+        type: 0
+      },
+      // 模型列表
+      modelList: [],
+      bagImg: '',
+      // 用户创建的角色列表
+      userCharacterList: [],
+      // 热门角色列表
+      characterList: [],
+      // 选中的角色对象
+      character: {},
+      // 上传图片相关↓
+      uploadUrl: process.env.VUE_APP_BASE_API + "/appUser/system/app/upload", // 上传的图片服务器地址
+      headers: {
+        UserToken: getToken()
+      },
+      uploadList: [],
+      fileSize: 5,
+      bgActive: 0
+    }
+  },
+  mounted() {
+    // 查询用户自己创建的角色
+    this.queryCharacters()
+    this.getModelList()
+    this.getCharacterList()
+    if (this.$route.query.characterId) {
+      this.getDetail(this.$route.query.characterId)
+      // this.character = {
+      //   id: this.$route.query.characterId,
+      // }
+      this.form.characterId = this.$route.query.characterId
+    }
+    if (this.$route.query.sceneId) {
+      this.getSceneDetai(this.$route.query.sceneId)
+    }
+  },
+  computed: {
+    nextDisabled() {
+      return this.form.sceneName == '' || this.form.sceneDescription == '' || this.form.sceneWelcome == '' || this.form.modelId == ''
+    }
+  },
+  methods: {
+    queryCharacters() {
+      let params = {
+        pageSize: 10,
+        pageNum: 1
+      }
+      queryCharactersApi(params).then(res => {
+        console.log(res, '人物列表');
+        this.userCharacterList = res.rows
+      })
+    },
+    getCharacterList(query) {
+      let params = {
+        pageSize: 10,
+        pageNum: 1
+      }
+      if (query) {
+        params = { ...params, ...query }
+      }
+      characterListApi(params).then(res => {
+        // console.log(res, '角色列表');
+        this.characterList = res.rows
+      })
+    },
+    getModelList() {
+      getModelListApi().then(res => {
+        console.log(res, '模型列表');
+        this.modelList = res.data
+      })
+    },
+    // 获取角色详情
+    getDetail(id) {
+      detailApi(id).then(res => {
+        console.log(res, '角色详情');
+        this.character = res.data
+      })
+    },
+    // 获取场景详情
+    getSceneDetai(id) {
+      getSceneDetailApi(id).then(res => {
+        console.log(res, '场景详情');
+        this.form = res.data
+        let backgroundArr = res.data.background.split('/')
+        this.uploadList.push({ name: backgroundArr[backgroundArr.length - 1], url: res.data.background });
+      })
+    },
+    // 选择角色
+    selectCharacter(value) {
+      console.log(value, 'value');
+      this.character = value
+      this.form.characterId = value.id
+      this.showPopup1 = false
+    },
+    handleCommand(value) {
+      this.form.type = value
+    },
+    // 下一步
+    next() {
+      this.active++
+    },
+    submit() {
+      this.form.background = this.uploadList[this.bgActive].url
+      if (this.form.sceneId) {
+        // 修改
+        editSceneApi(this.form).then(res => {
+          console.log(res, 'res>>>>>');
+          this.$message({
+            type: 'success',
+            message: '修改成功!'
+          });
+          this.$router.push('/profile')
+        })
+      } else {
+        // 新增
+        addSceneApi(this.form).then(res => {
+          console.log(res, 'res>>>>>');
+          this.$message({
+            type: 'success',
+            message: '发布成功!'
+          });
+          this.$router.push('/profile')
+        })
+      }
+    },
+    handleClickTab(tab, event) {
+
+    },
+    // 上传背景相关业务
+    // 上传前校检格式和大小
+    handleBeforeUpload(file) {
+      // 校检文件大小
+      if (this.fileSize) {
+        const isLt = file.size / 1024 / 1024 < this.fileSize;
+        if (!isLt) {
+          this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`);
+          return false;
+        }
+      }
+      return true;
+    },
+    // 上传成功回调
+    handleUploadSuccess(res, file) {
+      if (res.code === 200) {
+        this.uploadList.push({ name: res.originalFilename, url: res.fileName });
+        this.$message({
+          type: 'success',
+          message: '上传成功!'
+        });
+      } else {
+        this.$message({
+          type: 'error',
+          message: res.msg
+        });
+      }
+    },
+    // 上传结束处理
+    uploadedSuccessfully() {
+      console.log(this.uploadList, 'this.uploadList');
+      // this.$emit("input", this.listToString(this.fileList));
+      // this.$modal.closeLoading();
+    },
+    // 上传失败
+    handleUploadError() {
+      this.$modal.msgError("上传图片失败,请重试");
+    },
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.bottom {
+  height: 80px;
+}
+
+.characterName {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.bgActive {
+  border: solid 2px var(--bg-color1);
+}
+</style>
+<style scoped>
+.radio>>>.el-radio-button {
+  margin-bottom: 5px;
+  margin-right: 10px;
+  /* border-left: solid 1px #DCDFE6; */
+}
+
+.radio>>>.el-radio-button__inner {
+  border-left: solid 1px #DCDFE6;
+  border-radius: 4px;
+}
+
+.radio>>>.el-radio-button__orig-radio:checked+.el-radio-button__inner {
+  border-left: solid 1px var(--bg-color1);
+  background-color: var(--bg-color1);
+  border-color: var(--bg-color1);
+  -webkit-box-shadow: -1px 0 0 0 var(--bg-color1);
+  box-shadow: -1px 0 0 0 var(--bg-color1);
+}
+</style>

+ 16 - 386
src/views/profile/index.vue

@@ -1,402 +1,32 @@
-<!-- 个人中心 -->
 <template>
-  <div class=" h-full w-full">
-    <div class="h-72 relative text-white bg">
-      <img class=" absolute object-cover w-full h-full" v-if="userInfo.cover" :src="baseApi + userInfo.cover" alt="">
-      <div class="flex absolute bottom-0 w-full px-28 justify-between items-end">
-        <div class=" h-36 ">
-          <div class="flex justify-center">
-            <div class="w-24 h-24">
-              <img class="w-full h-full rounded-full" :src="$store.state.user.avatar" alt="">
-            </div>
-            <div class="flex flex-col justify-center ml-3">
-              <div class="font-medium text-2xl ">{{ userInfo.userName }}</div>
-              <div class="text-base">账号:{{ userInfo.account }}</div>
-              <div class=" text-base">UID:{{ userInfo.id }} <i class="el-icon-copy-document text-base"></i></div>
-            </div>
-          </div>
-          <div class="flex mt-3">
-            <div class=" text-sm">
-              关注: 15
-            </div>
-            <div class=" text-sm ml-4">
-              粉丝: 6
-            </div>
-          </div>
-        </div>
-        <div class="flex items-center h-20">
-          <div class=" w-10 h-10 rounded-full button flex justify-center items-center cursor-pointer mr-4">
-            <i class="el-icon-share text-xl"></i>
-          </div>
-          <div class="w-32 h-10 flex justify-center items-center rounded-full button cursor-pointer"
-            @click="$router.push({ name: 'user' })">
-            <i class="el-icon-edit"></i>
-            编辑资料
-          </div>
-        </div>
-      </div>
-    </div>
-
-    <div class="px-28 py-10">
-      <div class="h-18 flex justify-between pb-4 border-b border-gray-200">
-        <div class="flex justify-center">
-          <div class="labelButton flex justify-center items-center rounded-full mr-4 w-28 h-10 cursor-pointer"
-            :class="active == 0 && 'buttonBg1'" @click="tabChange(0)">
-            公开内容
-          </div>
-          <div class="labelButton flex justify-center items-center rounded-full w-28 h-10 cursor-pointer"
-            :class="active == 1 && 'buttonBg1'" @click="tabChange(1)">
-            <i class="el-icon-lock"></i>
-            非公开
-          </div>
-        </div>
-        <div class="flex justify-center">
-          <div class="text-gray-800 cursor-pointer">
-            <i class="el-icon-question"></i>
-            操作指南
-          </div>
-          <el-popover placement="bottom" width="160" v-model="popoverVisible">
-            <div class="flex flex-col">
-              <div class="submenu w-full text-gray-600 text-center py-2 rounded cursor-pointer" @click="() => {
-                popoverVisible = false
-                routeTo('/createScene')
-              }">
-                创建场景
-              </div>
-              <div class="submenu w-full text-gray-600 text-center py-2 rounded cursor-pointer" @click="() => {
-                popoverVisible = false
-                routeTo('/create')
-              }">
-                创建角色
-              </div>
-            </div>
-            <div slot="reference" class=" text-gray-800 cursor-pointer ml-4">
-              <i class="el-icon-plus"></i>
-              创建
-            </div>
-          </el-popover>
-
-        </div>
-      </div>
-      <div class="list mt-4">
-        <div v-for="(item, index) in characterList" :key="index"
-          class="box2 relative rounded-lg overflow-hidden shadow-lg cursor-pointer" @click="toDetail(item)">
-          <div class="w-full overflow-hidden h-3/5">
-            <img class="w-full img h-full" :src="baseApi + item.picture" />
-          </div>
-          <div class="p-2">
-            <h3 class="text-lg font-bold">
-              <i v-if="item.scene == 1" class="el-icon-video-camera"></i>
-              {{ item.name }}
-            </h3>
-            <p class="prologue text-sm">
-              {{ item.description }}
-            </p>
-
-            <div class="labels flex my-1 flex-wrap">
-              <div v-for="(item2, index2) in item.labelArr" :key="index2"
-                class="m-0.5 tag px-2 py-1 rounded flex items-center text-xs text-gray-500">
-                <!-- <i class="fas fa-smile text-yellow-400 mr-2"></i> -->
-                {{ item2 }}
-              </div>
-            </div>
-          </div>
-          <div class="absolute w-full bottom-0 flex items-center justify-between mt-3 px-3 pb-3">
-            <div class="flex items-center box1 text-red-500">
-              <v-icon name="fire" scale="1" />
-              <span class="ml-1">{{ item.hotCount || 0 }}</span>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-    <el-dialog title="提示" :visible.sync="dialogVisible" width="500px">
-      <div class="flex justify-between px-2 py-3 border-b border-gray-200" v-if="selectObj.scene == 1">
-        <div>场景</div>
-        <div>{{ selectObj.name }}</div>
-      </div>
-      <div class="flex justify-between px-2 py-3 border-b border-gray-200">
-        <div>角色</div>
-        <div>{{ selectObj.scene == 1 ? selectObj.characerName : selectObj.name }}</div>
-      </div>
-      <div class="flex justify-between px-2 py-3 border-b border-gray-200">
-        <div>可见性</div>
-        <el-radio-group v-model="selectObj.type" @input="typeChange">
-          <el-radio :label="0">公开</el-radio>
-          <el-radio :label="1">私密</el-radio>
-        </el-radio-group>
-      </div>
-      <div class="flex justify-between px-2 py-3 border-b border-gray-200">
-        <div></div>
-        <el-button round type="danger" @click="deleteData">删 除</el-button>
-      </div>
-      <span slot="footer" class="dialog-footer flex justify-around">
-        <el-button class="flex-1" round @click="toChat">聊 天</el-button>
-        <el-button class="flex-1" round type="primary" @click="toCreate">编 辑</el-button>
-      </span>
-    </el-dialog>
-
+  <div class="app-pageContainer">
+    <ProfilePC v-if="!$store.state.app.isMobile" />
+    <ProfileH5 v-else />
   </div>
 </template>
 
 <script>
-import { getInfo } from '@/api/login'
-import { queryCharacterAndSceneApi } from "@/api/profile.js"
-import {
-  deleteSceneApi,
-  deleteCharacterApi,
-  setCharacterShowApi,
-  editSceneApi
-} from "@/api/create.js"
-import 'vue-awesome/icons/fire'
+import ProfilePC from "./profilePC.vue"
+import ProfileH5 from "./profileH5.vue"
+
 export default {
+  name: "profile",
+  components: {
+    ProfilePC,
+    ProfileH5
+  },
   data() {
     return {
-      userInfo: {},
-      popoverVisible: false,
-      dialogVisible: false,
-      selectObj: {},
-      active: 0,
-      characterList: []
+
     }
   },
   mounted() {
-    this.getUserInfo()
-    this.getCharacterList()
+
   },
   methods: {
-    getUserInfo() {
-      let params = {
-        userId: this.$store.state.user.userId
-      }
-      getInfo(params).then(res => {
-        console.log(res, 'resUserInfo')
-        this.userInfo = res.data
-      })
-    },
-    routeTo(url) {
-      this.$router.push(url)
-    },
-
-    toDetail(item) {
-      console.log(item, 'item');
-      this.selectObj = item
-      this.dialogVisible = true
-    },
-    // 前往编辑页面
-    toCreate() {
-      if (this.selectObj.scene == 0) {
-        // 点击是角色
-        this.$router.push({
-          path: '/create',
-          query: {
-            id: this.selectObj.id
-          }
-        })
-      } else if (this.selectObj.scene == 1) {
-        // 点击是场景
-        this.$router.push({
-          path: '/createScene',
-          query: {
-            sceneId: this.selectObj.id,
-            characterId: this.selectObj.characterId
-          }
-        })
-      }
 
-    },
-    // 前往聊天页面
-    toChat() {
-      let query = {}
-      if (this.selectObj.scene == 0) {
-        // 点击是角色
-        query.characterId = this.selectObj.id
-      } else if (this.selectObj.scene == 1) {
-        // 点击是场景
-        query.characterId = this.selectObj.characterId
-        query.sceneId = this.selectObj.id
-      }
-      this.$router.push({
-        path: '/chat',
-        query: query
-      })
-    },
-    // 修改公开私密状态
-    typeChange() {
-      console.log(this.selectObj, 'this.selectObj');
-      if (this.selectObj.scene == 0) {
-        // 点击是角色
-        let params = {
-          id: this.selectObj.id,
-          type: this.selectObj.type
-        }
-        setCharacterShowApi(this.selectObj.id, this.selectObj.type).then(res => {
-          this.$message({
-            type: 'success',
-            message: '修改成功!'
-          });
-          this.dialogVisible = false
-          this.getCharacterList()
-        })
-      } else if (this.selectObj.scene == 1) {
-        // 点击是场景
-        let params = {
-          sceneId: this.selectObj.id,
-          type: this.selectObj.type
-        }
-        editSceneApi(params).then(res => {
-          this.$message({
-            type: 'success',
-            message: '修改成功!'
-          });
-          this.dialogVisible = false
-          this.getCharacterList()
-        })
-      }
-    },
-    // 删除
-    deleteData() {
-      if (this.selectObj.scene == 0) {
-        // 删除角色
-        this.$confirm('此操作将永久删除该角色及其所有聊天记录, 是否继续?', '提示', {
-          confirmButtonText: '确定',
-          cancelButtonText: '取消',
-          type: 'warning'
-        }).then(() => {
-          deleteCharacterApi(this.selectObj.id).then(res => {
-            this.$message({
-              type: 'success',
-              message: '删除成功!'
-            });
-            this.dialogVisible = false
-            this.getCharacterList()
-          })
-        })
-      } else if (this.selectObj.scene == 1) {
-        // 删除场景
-        this.$confirm('此操作将永久删除该场景及其所有聊天记录, 是否继续?', '提示', {
-          confirmButtonText: '确定',
-          cancelButtonText: '取消',
-          type: 'warning'
-        }).then(() => {
-          deleteSceneApi(this.selectObj.id).then(res => {
-            this.$message({
-              type: 'success',
-              message: '删除成功!'
-            });
-            this.dialogVisible = false
-            this.getCharacterList()
-          })
-        })
-
-      }
-    },
-    tabChange(index) {
-      this.active = index
-      this.getCharacterList()
-    },
-    getCharacterList(query) {
-      let params = {
-        pageSize: 20,
-        pageNum: 1,
-        type: this.active
-      }
-      if (query) {
-        params = {
-          ...params,
-          ...query
-        }
-      }
-      queryCharacterAndSceneApi(params).then(res => {
-        console.log(res, '角色列表');
-        // let characterList = res.data.characterList
-        // characterList.map((item) => { item.mType = 1 })
-        // let sceneList = res.data.sceneList
-        // sceneList.map((item) => { item.mType = 2 })
-        // let arr = [
-        //   ...res.data.characterList,
-        //   ...res.data.sceneList,
-        // ]
-        // arr.sort(this.sortByTime('createTime', -1))
-        this.characterList = res.rows
-      })
-    },
-    sortByTime(attr, rev) {
-      //attr:根据该属性排序;rev:升序1或降序-1,不填则默认为1
-      if (rev == undefined) { rev = 1 } else { (rev) ? 1 : -1; }
-      return function (a, b) {
-        a = new Date(a[attr]).getTime();
-        b = new Date(b[attr]).getTime();
-        if (a < b) { return rev * -1 }
-        if (a > b) { return rev * 1 }
-        return 0;
-      }
-    }
-  }
-}
+  },
+};
 </script>
 
-<style lang="scss" scoped>
-.list {
-  display: grid;
-  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
-  grid-auto-rows: minmax(100px, auto);
-  grid-gap: 20px;
-}
-
-.button {
-  // background-color: #fff;
-  color: #fff;
-  border: 1px solid #fff;
-}
-
-.labelButton {
-  // border: solid 1px #e6e6e6;
-  background: var(--bg-color2);
-  color: var(--color2);
-}
-
-.buttonBg1 {
-  background: var(--bg-color1);
-  color: #fff;
-}
-
-.box2 {
-  background: #ffffff0f;
-  border: 1px solid #ffffff2e;
-  min-width: 200px;
-  height: 35vw;
-  min-height: 260px;
-  max-height: 400px;
-}
-
-.box2:hover {
-  border: solid 1px var(--bg-color1);
-}
-
-.img {
-  // height: 230px;
-  object-fit: cover;
-  object-position: top;
-  transition: transform .2s
-}
-
-.img:hover {
-  transform: scale(1.1);
-}
-
-.bg {
-  background-color: var(--bg-color1);
-  background-image: url(https://cdn-az.rochat.tech/avatar/131__c9103616-e103-11ee-bef2-66a40ff97e79.png);
-  background-repeat: no-repeat;
-  background-size: 100% 100%;
-}
-
-.prologue {
-  overflow: hidden;
-  text-overflow: ellipsis;
-  -webkit-line-clamp: 4;
-  display: -webkit-box;
-  -webkit-box-orient: vertical;
-}
-</style>
+<style scoped lang="scss"></style>

+ 247 - 0
src/views/profile/profileH5.vue

@@ -0,0 +1,247 @@
+<template>
+  <div class="profileH5 bg-white" style="min-height: 100vh;">
+    <div class="title">
+      <div>我的</div>
+    </div>
+    <el-tabs v-model="query.type" @tab-click="tabChange" class="tabs w-full">
+      <el-tab-pane label="公开" :name="0"></el-tab-pane>
+      <el-tab-pane label="非公开" :name="1"></el-tab-pane>
+    </el-tabs>
+    <div class="lietRom flex-1 overflow-auto" v-infinite-scroll="load" infinite-scroll-disabled="disabled">
+      <div class="list mt-4">
+        <div v-for="(item, index) in characterList" :key="index"
+          class="box2 relative rounded-lg overflow-hidden shadow-lg cursor-pointer" @click="toDetail(item)">
+          <div class="w-full overflow-hidden">
+            <img :src="baseApi + item.picture" class="w-full img" />
+          </div>
+          <div class="p-2">
+            <h3 class="text-lg font-bold flex items-center">
+              <div style="max-width: calc(100% - 18px);">{{ item.name }}</div>
+              <i v-if="item.scene == 1" class="el-icon-video-camera-solid"></i>
+              <i v-if="item.scene == 0" class="el-icon-user-solid"></i>
+            </h3>
+            <p class="prologue text-sm">
+              {{ item.description }}
+            </p>
+            <div class="labels flex my-1 flex-wrap">
+              <div v-for="(item2, index2) in item.labelArr" :key="index2"
+                class="m-0.5 tag px-2 py-1 rounded flex items-center text-xs text-gray-500">
+                <!-- <i class="fas fa-smile text-yellow-400 mr-2"></i> -->
+                {{ item2 }}
+              </div>
+            </div>
+          </div>
+          <div class="absolute w-full bottom-0 flex items-center justify-between mt-3 px-2 pb-2">
+            <div></div>
+            <div class="flex items-center box1 text-red-500">
+              <v-icon name="fire" scale="1" />
+              <span class="ml-1">{{ item.hotCount || 0 }}</span>
+            </div>
+          </div>
+        </div>
+      </div>
+      <p class="w-full py-4 text-gray-400 text-center" v-if="loading">加载中...</p>
+      <p class="w-full py-4 text-gray-400 text-center" v-if="noMore">没有更多了</p>
+    </div>
+  </div>
+</template>
+
+<script>
+import { queryCharacterAndSceneApi } from "@/api/profile.js"
+export default {
+  data() {
+    return {
+      query: {
+        pageSize: 10,
+        pageNum: 2,
+        type: 0
+      },
+      total: 0,
+      loading: false,
+      noMore: false,
+      characterList: []
+    }
+  },
+  computed: {
+    disabled() {
+      return this.loading || this.noMore
+    }
+  },
+  mounted() {
+    this.getCharacterList()
+  },
+  methods: {
+    tabChange() {
+      this.query.pageNum = 1
+      this.characterList = []
+      this.getCharacterList()
+    },
+    load() {
+      this.query.pageNum += 1
+      this.getCharacterList()
+    },
+    getCharacterList(query) {
+      this.loading = true
+      let params = this.query
+      if (query) {
+        params = {
+          ...params,
+          ...query,
+
+        }
+      }
+      queryCharacterAndSceneApi(params).then(res => {
+        console.log(res, '角色列表');
+        if (res.rows.length == 0) {
+          this.noMore = true
+        }
+        // this.characterList = res.rows
+        this.characterList = [...this.characterList, ...res.rows]
+        if (this.characterList.length >= res.total) {
+          this.noMore = true
+        }
+        this.total = res.total
+        this.loading = false
+      })
+    },
+    toDetail(item) {
+      console.log(item, 'item');
+      this.selectObj = item
+      this.toChat()
+      // this.dialogVisible = true
+    },
+    // 前往聊天页面
+    toChat() {
+      let query = {}
+      if (this.selectObj.scene == 0) {
+        // 点击是角色
+        query.characterId = this.selectObj.id
+        this.$router.push({
+          path: '/chatH5',
+          query: query
+        })
+      } else if (this.selectObj.scene == 1) {
+        // 点击是场景
+        query.characterId = this.selectObj.characterId
+        query.sceneId = this.selectObj.id
+        this.$router.push({
+          path: '/chat',
+          query: query
+        })
+      }
+
+    },
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.profileH5 {
+  .title {
+    height: 40px;
+    line-height: 40px;
+    font-size: 16px;
+    // font-weight: 600;
+    text-align: center;
+  }
+
+  .tabs {}
+}
+
+.lietRom {
+  padding: 5px;
+  padding-bottom: 60px;
+}
+
+.lietRom::-webkit-scrollbar {
+  display: none;
+}
+
+.textButton {
+  // color: #eee;
+  margin-left: 5px;
+}
+
+.textButton:hover {
+  color: #9333ea;
+}
+
+.labelButton {
+  border: solid 1px #e6e6e6;
+  background: var(--bg-color2);
+}
+
+.buttonBg1 {
+  background: var(--bg-color1);
+  color: #fff;
+}
+
+.topActive {
+  background: var(--bg-color1);
+}
+
+.tag {
+  background: var(--bg-color2);
+}
+
+.box1 {
+  border: 1px solid #ffffff4d;
+  height: 30px;
+  padding: 0 10px;
+  border-radius: 18px;
+  // width: 68px;
+  font-size: 14px;
+}
+
+.box2 {
+  background: #ffffff0f;
+  border: 1px solid #ffffff2e;
+  height: 380px;
+}
+
+.box2:hover {
+  border: solid 1px var(--bg-color1);
+}
+
+.img {
+  height: 200px;
+  object-fit: cover;
+  object-position: top;
+  transition: transform .2s
+}
+
+.img:hover {
+  transform: scale(1.1);
+}
+
+.labels {
+  max-height: 56px;
+  overflow-y: auto;
+}
+
+.prologue {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  -webkit-line-clamp: 2;
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+}
+</style>
+<style scoped>
+.list {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  /* grid-auto-rows: minmax(280px, 280px); */
+  grid-gap: 10px;
+}
+
+.tabs>>>.el-tabs__nav {
+  width: 100%;
+}
+
+.tabs>>>.el-tabs__item {
+  width: 50%;
+  padding: 0;
+  text-align: center;
+}
+</style>

+ 402 - 0
src/views/profile/profilePC.vue

@@ -0,0 +1,402 @@
+<!-- 个人中心 -->
+<template>
+  <div class=" h-full w-full">
+    <div class="h-72 relative text-white bg">
+      <img class=" absolute object-cover w-full h-full" v-if="userInfo.cover" :src="baseApi + userInfo.cover" alt="">
+      <div class="flex absolute bottom-0 w-full px-28 justify-between items-end">
+        <div class=" h-36 ">
+          <div class="flex justify-center">
+            <div class="w-24 h-24">
+              <img class="w-full h-full rounded-full" :src="$store.state.user.avatar" alt="">
+            </div>
+            <div class="flex flex-col justify-center ml-3">
+              <div class="font-medium text-2xl ">{{ userInfo.userName }}</div>
+              <div class="text-base">账号:{{ userInfo.account }}</div>
+              <div class=" text-base">UID:{{ userInfo.id }} <i class="el-icon-copy-document text-base"></i></div>
+            </div>
+          </div>
+          <div class="flex mt-3">
+            <div class=" text-sm">
+              关注: 15
+            </div>
+            <div class=" text-sm ml-4">
+              粉丝: 6
+            </div>
+          </div>
+        </div>
+        <div class="flex items-center h-20">
+          <div class=" w-10 h-10 rounded-full button flex justify-center items-center cursor-pointer mr-4">
+            <i class="el-icon-share text-xl"></i>
+          </div>
+          <div class="w-32 h-10 flex justify-center items-center rounded-full button cursor-pointer"
+            @click="$router.push({ name: 'user' })">
+            <i class="el-icon-edit"></i>
+            编辑资料
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="px-28 py-10">
+      <div class="h-18 flex justify-between pb-4 border-b border-gray-200">
+        <div class="flex justify-center">
+          <div class="labelButton flex justify-center items-center rounded-full mr-4 w-28 h-10 cursor-pointer"
+            :class="active == 0 && 'buttonBg1'" @click="tabChange(0)">
+            公开内容
+          </div>
+          <div class="labelButton flex justify-center items-center rounded-full w-28 h-10 cursor-pointer"
+            :class="active == 1 && 'buttonBg1'" @click="tabChange(1)">
+            <i class="el-icon-lock"></i>
+            非公开
+          </div>
+        </div>
+        <div class="flex justify-center">
+          <div class="text-gray-800 cursor-pointer">
+            <i class="el-icon-question"></i>
+            操作指南
+          </div>
+          <el-popover placement="bottom" width="160" v-model="popoverVisible">
+            <div class="flex flex-col">
+              <div class="submenu w-full text-gray-600 text-center py-2 rounded cursor-pointer" @click="() => {
+                popoverVisible = false
+                routeTo('/createScene')
+              }">
+                创建场景
+              </div>
+              <div class="submenu w-full text-gray-600 text-center py-2 rounded cursor-pointer" @click="() => {
+                popoverVisible = false
+                routeTo('/create')
+              }">
+                创建角色
+              </div>
+            </div>
+            <div slot="reference" class=" text-gray-800 cursor-pointer ml-4">
+              <i class="el-icon-plus"></i>
+              创建
+            </div>
+          </el-popover>
+
+        </div>
+      </div>
+      <div class="list mt-4">
+        <div v-for="(item, index) in characterList" :key="index"
+          class="box2 relative rounded-lg overflow-hidden shadow-lg cursor-pointer" @click="toDetail(item)">
+          <div class="w-full overflow-hidden h-3/5">
+            <img class="w-full img h-full" :src="baseApi + item.picture" />
+          </div>
+          <div class="p-2">
+            <h3 class="text-lg font-bold">
+              <i v-if="item.scene == 1" class="el-icon-video-camera"></i>
+              {{ item.name }}
+            </h3>
+            <p class="prologue text-sm">
+              {{ item.description }}
+            </p>
+
+            <div class="labels flex my-1 flex-wrap">
+              <div v-for="(item2, index2) in item.labelArr" :key="index2"
+                class="m-0.5 tag px-2 py-1 rounded flex items-center text-xs text-gray-500">
+                <!-- <i class="fas fa-smile text-yellow-400 mr-2"></i> -->
+                {{ item2 }}
+              </div>
+            </div>
+          </div>
+          <div class="absolute w-full bottom-0 flex items-center justify-between mt-3 px-3 pb-3">
+            <div class="flex items-center box1 text-red-500">
+              <v-icon name="fire" scale="1" />
+              <span class="ml-1">{{ item.hotCount || 0 }}</span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <el-dialog title="提示" :visible.sync="dialogVisible" width="500px">
+      <div class="flex justify-between px-2 py-3 border-b border-gray-200" v-if="selectObj.scene == 1">
+        <div>场景</div>
+        <div>{{ selectObj.name }}</div>
+      </div>
+      <div class="flex justify-between px-2 py-3 border-b border-gray-200">
+        <div>角色</div>
+        <div>{{ selectObj.scene == 1 ? selectObj.characerName : selectObj.name }}</div>
+      </div>
+      <div class="flex justify-between px-2 py-3 border-b border-gray-200">
+        <div>可见性</div>
+        <el-radio-group v-model="selectObj.type" @input="typeChange">
+          <el-radio :label="0">公开</el-radio>
+          <el-radio :label="1">私密</el-radio>
+        </el-radio-group>
+      </div>
+      <div class="flex justify-between px-2 py-3 border-b border-gray-200">
+        <div></div>
+        <el-button round type="danger" @click="deleteData">删 除</el-button>
+      </div>
+      <span slot="footer" class="dialog-footer flex justify-around">
+        <el-button class="flex-1" round @click="toChat">聊 天</el-button>
+        <el-button class="flex-1" round type="primary" @click="toCreate">编 辑</el-button>
+      </span>
+    </el-dialog>
+
+  </div>
+</template>
+
+<script>
+import { getInfo } from '@/api/login'
+import { queryCharacterAndSceneApi } from "@/api/profile.js"
+import {
+  deleteSceneApi,
+  deleteCharacterApi,
+  setCharacterShowApi,
+  editSceneApi
+} from "@/api/create.js"
+import 'vue-awesome/icons/fire'
+export default {
+  data() {
+    return {
+      userInfo: {},
+      popoverVisible: false,
+      dialogVisible: false,
+      selectObj: {},
+      active: 0,
+      characterList: []
+    }
+  },
+  mounted() {
+    this.getUserInfo()
+    this.getCharacterList()
+  },
+  methods: {
+    getUserInfo() {
+      let params = {
+        userId: this.$store.state.user.userId
+      }
+      getInfo(params).then(res => {
+        console.log(res, 'resUserInfo')
+        this.userInfo = res.data
+      })
+    },
+    routeTo(url) {
+      this.$router.push(url)
+    },
+
+    toDetail(item) {
+      console.log(item, 'item');
+      this.selectObj = item
+      this.dialogVisible = true
+    },
+    // 前往编辑页面
+    toCreate() {
+      if (this.selectObj.scene == 0) {
+        // 点击是角色
+        this.$router.push({
+          path: '/create',
+          query: {
+            id: this.selectObj.id
+          }
+        })
+      } else if (this.selectObj.scene == 1) {
+        // 点击是场景
+        this.$router.push({
+          path: '/createScene',
+          query: {
+            sceneId: this.selectObj.id,
+            characterId: this.selectObj.characterId
+          }
+        })
+      }
+
+    },
+    // 前往聊天页面
+    toChat() {
+      let query = {}
+      if (this.selectObj.scene == 0) {
+        // 点击是角色
+        query.characterId = this.selectObj.id
+      } else if (this.selectObj.scene == 1) {
+        // 点击是场景
+        query.characterId = this.selectObj.characterId
+        query.sceneId = this.selectObj.id
+      }
+      this.$router.push({
+        path: '/chat',
+        query: query
+      })
+    },
+    // 修改公开私密状态
+    typeChange() {
+      console.log(this.selectObj, 'this.selectObj');
+      if (this.selectObj.scene == 0) {
+        // 点击是角色
+        let params = {
+          id: this.selectObj.id,
+          type: this.selectObj.type
+        }
+        setCharacterShowApi(this.selectObj.id, this.selectObj.type).then(res => {
+          this.$message({
+            type: 'success',
+            message: '修改成功!'
+          });
+          this.dialogVisible = false
+          this.getCharacterList()
+        })
+      } else if (this.selectObj.scene == 1) {
+        // 点击是场景
+        let params = {
+          sceneId: this.selectObj.id,
+          type: this.selectObj.type
+        }
+        editSceneApi(params).then(res => {
+          this.$message({
+            type: 'success',
+            message: '修改成功!'
+          });
+          this.dialogVisible = false
+          this.getCharacterList()
+        })
+      }
+    },
+    // 删除
+    deleteData() {
+      if (this.selectObj.scene == 0) {
+        // 删除角色
+        this.$confirm('此操作将永久删除该角色及其所有聊天记录, 是否继续?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        }).then(() => {
+          deleteCharacterApi(this.selectObj.id).then(res => {
+            this.$message({
+              type: 'success',
+              message: '删除成功!'
+            });
+            this.dialogVisible = false
+            this.getCharacterList()
+          })
+        })
+      } else if (this.selectObj.scene == 1) {
+        // 删除场景
+        this.$confirm('此操作将永久删除该场景及其所有聊天记录, 是否继续?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+        }).then(() => {
+          deleteSceneApi(this.selectObj.id).then(res => {
+            this.$message({
+              type: 'success',
+              message: '删除成功!'
+            });
+            this.dialogVisible = false
+            this.getCharacterList()
+          })
+        })
+
+      }
+    },
+    tabChange(index) {
+      this.active = index
+      this.getCharacterList()
+    },
+    getCharacterList(query) {
+      let params = {
+        pageSize: 20,
+        pageNum: 1,
+        type: this.active
+      }
+      if (query) {
+        params = {
+          ...params,
+          ...query
+        }
+      }
+      queryCharacterAndSceneApi(params).then(res => {
+        console.log(res, '角色列表');
+        // let characterList = res.data.characterList
+        // characterList.map((item) => { item.mType = 1 })
+        // let sceneList = res.data.sceneList
+        // sceneList.map((item) => { item.mType = 2 })
+        // let arr = [
+        //   ...res.data.characterList,
+        //   ...res.data.sceneList,
+        // ]
+        // arr.sort(this.sortByTime('createTime', -1))
+        this.characterList = res.rows
+      })
+    },
+    sortByTime(attr, rev) {
+      //attr:根据该属性排序;rev:升序1或降序-1,不填则默认为1
+      if (rev == undefined) { rev = 1 } else { (rev) ? 1 : -1; }
+      return function (a, b) {
+        a = new Date(a[attr]).getTime();
+        b = new Date(b[attr]).getTime();
+        if (a < b) { return rev * -1 }
+        if (a > b) { return rev * 1 }
+        return 0;
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.list {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
+  grid-auto-rows: minmax(100px, auto);
+  grid-gap: 20px;
+}
+
+.button {
+  // background-color: #fff;
+  color: #fff;
+  border: 1px solid #fff;
+}
+
+.labelButton {
+  // border: solid 1px #e6e6e6;
+  background: var(--bg-color2);
+  color: var(--color2);
+}
+
+.buttonBg1 {
+  background: var(--bg-color1);
+  color: #fff;
+}
+
+.box2 {
+  background: #ffffff0f;
+  border: 1px solid #ffffff2e;
+  min-width: 200px;
+  height: 35vw;
+  min-height: 260px;
+  max-height: 400px;
+}
+
+.box2:hover {
+  border: solid 1px var(--bg-color1);
+}
+
+.img {
+  // height: 230px;
+  object-fit: cover;
+  object-position: top;
+  transition: transform .2s
+}
+
+.img:hover {
+  transform: scale(1.1);
+}
+
+.bg {
+  background-color: var(--bg-color1);
+  background-image: url(https://cdn-az.rochat.tech/avatar/131__c9103616-e103-11ee-bef2-66a40ff97e79.png);
+  background-repeat: no-repeat;
+  background-size: 100% 100%;
+}
+
+.prologue {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  -webkit-line-clamp: 4;
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+}
+</style>