0bf5897786ede4066059e451fe5c651f9c338393..4d0ebb399281589564d6fa9d512c375a28abc303
2025-05-30 Flex
补充提交
4d0ebb 对比 | 目录
2025-05-30 Flex
补充提交登录页
5a2169 对比 | 目录
2025-05-30 Flex
补充提交
a8ce6d 对比 | 目录
2025-05-30 Flex
修改登录页
c20847 对比 | 目录
2025-05-30 du
Merge remote-tracking branch 'origin/master'
444fee 对比 | 目录
2025-05-30 du
模板管理的新增创建人字段
1989ea 对比 | 目录
2025-05-30 康鲁杰
Merge remote-tracking branch 'origin/master'
45b5f1 对比 | 目录
2025-05-30 康鲁杰
模版管理权限
8a7da9 对比 | 目录
2025-05-30 Flex
Merge branch 'master' of http://yykjgit.sdyyst.com/r/easegen
82506d 对比 | 目录
2025-05-30 Flex
补充提交
909a7c 对比 | 目录
2025-05-30 du
Merge remote-tracking branch 'origin/master'
65af7b 对比 | 目录
2025-05-30 du
模板管理的模板类型修改 课程中心的模板设置修改模板类型
6c11e2 对比 | 目录
2025-05-30 Flex
Merge branch 'master' of http://yykjgit.sdyyst.com/r/easegen
dd325a 对比 | 目录
2025-05-30 Flex
修改登录页样式
421c5c 对比 | 目录
2025-05-29 du
Merge remote-tracking branch 'origin/master'
cb4ca5 对比 | 目录
2025-05-29 du
数字人的背景样式
2fc29e 对比 | 目录
2025-05-29 康鲁杰
背景样式
19a44b 对比 | 目录
2025-05-29 康鲁杰
Merge remote-tracking branch 'origin/master'
0d9844 对比 | 目录
2025-05-29 康鲁杰
视频只有一帧问题
c4ccbb 对比 | 目录
2025-05-29 du
模板管理加修改功能和页面 课程中心去除背景和画中画设置,去除模板的上传音频功能
5fae48 对比 | 目录
2025-05-28 du
课程中心,修改数字人和模板样式并加上空状态判断
1fe6ba 对比 | 目录
2025-05-28 shenrongliang
修改查询数字人类型,视频合成层级
76f6a3 对比 | 目录
已修改20个文件
已添加1个文件
已删除2个文件
884 ■■■■■ 文件已修改
easegen-front/src/assets/imgs/bei3-1.png 补丁 | 查看 | 原始文档 | blame | 历史
easegen-front/src/assets/imgs/bei3.png 补丁 | 查看 | 原始文档 | blame | 历史
easegen-front/src/assets/imgs/bei4.png 补丁 | 查看 | 原始文档 | blame | 历史
easegen-front/src/views/Login/Login.vue 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easegen-front/src/views/Login/components/LoginForm.vue 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easegen-front/src/views/Login/components/LoginFormTitle.vue 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easegen-front/src/views/chooseTemplate/index.vue 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easegen-front/src/views/dialogue/index.vue 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easegen-front/src/views/digitalcourse/digitalhumans/LookDigitalHumansForm.vue 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easegen-front/src/views/digitalcourse/digitalhumans/index.vue 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easegen-front/src/views/digitalcourse/template/TemplateForm.vue 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
easegen-front/src/views/digitalcourse/template/index.vue 272 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/controller/admin/digitalhumans/vo/DigitalHumansRespVO.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/controller/admin/template/TemplateController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/controller/admin/template/vo/TemplatePageReqVO.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/controller/admin/template/vo/TemplateRespVO.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/controller/admin/template/vo/TemplateSaveReqVO.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/dal/dataobject/template/TemplateDO.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/dal/mysql/template/TemplateMapper.java 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/coursemedia/CourseMediaServiceUtil.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/digitalhumans/DigitalHumansServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/template/TemplateServiceImpl.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/util/PPTUtil.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
easegen-front/src/assets/imgs/bei3-1.png
easegen-front/src/assets/imgs/bei3.png
Binary files differ
easegen-front/src/assets/imgs/bei4.png
Binary files differ
easegen-front/src/views/Login/Login.vue
@@ -1,9 +1,11 @@
<template>
  <div class="bei">
      <div class="">
      <div class="BeiArea">
        <!-- 左侧图片 -->
         <div class="Left-img" >
            <img src="@/assets/imgs/bei4.png" alt=""/>
         <div class="Left-img">
            <div class="TitleText" >
              <text> 数字人 </text>智能交互平台
            </div>
         </div>
        <!-- 右边的登录界面 -->
        <Transition appear enter-active-class="animate__animated animate__bounceInRight">
@@ -25,7 +27,6 @@
</template>
<script lang="ts" setup>
import { underlineToHump } from '@/utils'
import { useDesign } from '@/hooks/web/useDesign'
import { useAppStore } from '@/store/modules/app'
import { ThemeSwitch } from '@/layout/components/ThemeSwitch'
@@ -58,45 +59,74 @@
.bei{
  width: 100%;
  height: 100%;
  background-image: url('@/assets/imgs/bei3.png');
  background-size: 100% 100%;
  background-repeat: no-repeat;
  background-color: #000;
  display: flex;
  justify-content: center;
  align-items: center;
}
.form-box{
  width: 25%;
  padding: 20px;
.bei .BeiArea{
  width: 86%;
  height: 95%;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #000a25;
}
.bei .BeiArea .form-box{
  /* width: 25%; */
  width: 400px;
  margin-top: -36px;
  padding: 70px 30px;
  box-sizing: border-box;
  background: #fff;
  float: right;
  margin-top: 30vh;
  margin-right: 10vw;
  margin-left: 300px;
  box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;
}
.Left-img{
  float: left;
  width: 50%;
  margin-top: 4vh;
  margin-left: 60px;
.bei .BeiArea .Left-img{
  width: 729px;
  height: 655px;
  margin-top: 138px;
  margin-left: -74px;
  background-image:url( "@/assets/imgs/bei3-1.png" );
  /* background-size: 100%; */
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center center;
  display: flex;
  justify-content: center;
  align-items: center;
}
.Left-img img{
.bei .BeiArea .Left-img .TitleText{
  margin-top: calc( -85% );
  margin-left: -60px;
  color: #fff;
  width: 100%;
  text-align: left;
  font-size: 48px;
  padding-left: 10%;
  box-sizing: border-box;
}
.bei .BeiArea .Left-img .TitleText text{
  color: #2d84fa;
}
@media screen and ( max-width: 1300px )  {
  .form-box{
    width: 80%;
    float: left;
    margin-left: 10%;
    margin-right: 0;
    margin-top: calc( 50vh - 100px );
    width: 50% !important;
    margin: 0 auto !important;
  }
  .Left-img{
    display: none;
    display: none !important;
  }
  
}
@media (max-width:1650px) and ( min-width: 1300px )  {
  .bei .BeiArea .Left-img{
    margin-left: 0;
  }
}
</style>
easegen-front/src/views/Login/components/LoginForm.vue
@@ -4,7 +4,7 @@
    ref="formLogin"
    :model="loginData.loginForm"
    :rules="LoginRules"
    class="login-form"
    class="login-form NewClass"
    label-position="top"
    label-width="120px"
    size="large"
@@ -59,7 +59,7 @@
              </el-checkbox>
            </el-col>
            <el-col :offset="6" :span="12">
              <el-link style="float: right" type="primary">{{ t('login.forgetPassword') }}</el-link>
              <!-- <el-link style="float: right" type="primary">{{ t('login.forgetPassword') }}</el-link> -->
            </el-col>
          </el-row>
        </el-form-item>
@@ -72,6 +72,7 @@
            class="w-[100%]"
            type="primary"
            @click="getCode()"
            style="background-color: #1d78f4"
          />
        </el-form-item>
      </el-col>
@@ -82,9 +83,10 @@
        mode="pop"
        @success="handleLogin"
      />
      <el-col :span="24" style="padding-right: 10px; padding-left: 10px">
      <!-- 注册不显示 -->
      <!-- <el-col :span="24"  >
        <el-form-item>
          <el-row :gutter="5" justify="space-between" style="width: 100%">
          <el-row :gutter="5" justify="space-between" style="width: 100%; margin-left: 0 !important;">
            <el-col :span="12">
              <XButton
                :title="t('login.btnMobile')"
@@ -92,14 +94,14 @@
                @click="setLoginState(LoginStateEnum.MOBILE)"
              />
            </el-col>
<!--            <el-col :span="8">-->
<!--              <XButton-->
<!--                :title="t('login.btnQRCode')"-->
<!--                class="w-[100%]"-->
<!--                @click="setLoginState(LoginStateEnum.QR_CODE)"-->
<!--              />-->
<!--            </el-col>-->
            <el-col :span="12">
                       <el-col :span="8">
                         <XButton
                           :title="t('login.btnQRCode')"
                           class="w-[100%]"
                           @click="setLoginState(LoginStateEnum.QR_CODE)"
                         />
                       </el-col>
            <el-col :span="24"  style="padding-right: 10px; padding-left: 10px" >
              <XButton
                :title="t('login.btnRegister')"
                class="w-[100%]"
@@ -108,38 +110,38 @@
            </el-col>
          </el-row>
        </el-form-item>
      </el-col>
<!--      <el-divider content-position="center">{{ t('login.otherLogin') }}</el-divider>-->
<!--      <el-col :span="24" style="padding-right: 10px; padding-left: 10px">-->
<!--        <el-form-item>-->
<!--          <div class="w-[100%] flex justify-between">-->
<!--            <Icon-->
<!--              v-for="(item, key) in socialList"-->
<!--              :key="key"-->
<!--              :icon="item.icon"-->
<!--              :size="30"-->
<!--              class="anticon cursor-pointer"-->
<!--              color="#999"-->
<!--              @click="doSocialLogin(item.type)"-->
<!--            />-->
<!--          </div>-->
<!--        </el-form-item>-->
<!--      </el-col>-->
<!--      <el-divider content-position="center">萌新必读</el-divider>-->
<!--      <el-col :span="24" style="padding-right: 10px; padding-left: 10px">-->
<!--        <el-form-item>-->
<!--          <div class="w-[100%] flex justify-between">-->
<!--            <el-link href="https://doc.iocoder.cn/" target="_blank">📚开发指南</el-link>-->
<!--            <el-link href="https://doc.iocoder.cn/video/" target="_blank">🔥视频教程</el-link>-->
<!--            <el-link href="https://www.iocoder.cn/Interview/good-collection/" target="_blank">-->
<!--              ⚡面试手册-->
<!--            </el-link>-->
<!--            <el-link href="http://static.yudao.iocoder.cn/mp/Aix9975.jpeg" target="_blank">-->
<!--              🤝外包咨询-->
<!--            </el-link>-->
<!--          </div>-->
<!--        </el-form-item>-->
<!--      </el-col>-->
      </el-col> -->
      <!--      <el-divider content-position="center">{{ t('login.otherLogin') }}</el-divider>-->
      <!--      <el-col :span="24" style="padding-right: 10px; padding-left: 10px">-->
      <!--        <el-form-item>-->
      <!--          <div class="w-[100%] flex justify-between">-->
      <!--            <Icon-->
      <!--              v-for="(item, key) in socialList"-->
      <!--              :key="key"-->
      <!--              :icon="item.icon"-->
      <!--              :size="30"-->
      <!--              class="anticon cursor-pointer"-->
      <!--              color="#999"-->
      <!--              @click="doSocialLogin(item.type)"-->
      <!--            />-->
      <!--          </div>-->
      <!--        </el-form-item>-->
      <!--      </el-col>-->
      <!--      <el-divider content-position="center">萌新必读</el-divider>-->
      <!--      <el-col :span="24" style="padding-right: 10px; padding-left: 10px">-->
      <!--        <el-form-item>-->
      <!--          <div class="w-[100%] flex justify-between">-->
      <!--            <el-link href="https://doc.iocoder.cn/" target="_blank">📚开发指南</el-link>-->
      <!--            <el-link href="https://doc.iocoder.cn/video/" target="_blank">🔥视频教程</el-link>-->
      <!--            <el-link href="https://www.iocoder.cn/Interview/good-collection/" target="_blank">-->
      <!--              ⚡面试手册-->
      <!--            </el-link>-->
      <!--            <el-link href="http://static.yudao.iocoder.cn/mp/Aix9975.jpeg" target="_blank">-->
      <!--              🤝外包咨询-->
      <!--            </el-link>-->
      <!--          </div>-->
      <!--        </el-form-item>-->
      <!--      </el-col>-->
    </el-row>
  </el-form>
</template>
@@ -352,4 +354,42 @@
    cursor: pointer;
  }
}
.NewClass {
  ::v-deep(.el-input__inner) {
    font-size: 20px;
    line-height: 40px;
    height: 60px;
  }
  ::v-deep(.el-button--large) {
    padding: 20px;
    box-sizing: border-box;
    font-size: 20px;
    height: 60px;
    margin-top: 20px;
  }
}
@media screen and (max-width: 1300px) {
  .NewClass {
    ::v-deep(.el-input__inner) {
      font-size: 20px;
      line-height: 40px;
      height: 50px;
    }
    ::v-deep(.el-form-item--large){
      margin-bottom: 40px;
    }
    ::v-deep(.el-checkbox__label){
      font-size: 18px;
    }
    ::v-deep(.el-button--large) {
      padding: 20px;
      box-sizing: border-box;
      font-size: 20px;
      height: 60px;
      margin-top: 10px;
    }
  }
}
</style>
easegen-front/src/views/Login/components/LoginFormTitle.vue
@@ -1,5 +1,12 @@
<style>
.c717a8a{
  color: #717a8a
}
</style>
<template>
  <h2 class="enter-x mb-3 text-center text-2xl font-bold xl:text-center xl:text-3xl">
  <h2 class="enter-x mb-3 text-2xl font-bold xl:text-3xl c717a8a"  >
    {{ getFormTitle }}
  </h2>
</template>
easegen-front/src/views/chooseTemplate/index.vue
@@ -474,6 +474,7 @@
              }"
            />
          </div>
          <el-empty v-if="hostList.length==0" description="暂无数据" />
          <Pagination
            small="true"
            :total="total"
@@ -487,10 +488,25 @@
      <div class="template-box template-right" v-if="showTemplateTool">
        <div class="tabs-2"> </div>
        <div class="template-list">
          <div class="tabs-1">
            <div
              class="tabs-item"
              v-for="item in tabs4"
              :key="item.itemValue"
              @click="tabs4Click(item)"
            >
              <div>{{ item.itemName }}</div>
              <span v-if="tabs4ActiveNum == item.itemValue"></span>
            </div>
          </div>
          <div
            class="template-item"
            v-for="(template, index) in templates"
            :key="index"
            :style="{
                width: '90%',
                maxWidth: '90%',
              }"
            @click="handleTemplateSelection(template)"
          >
            <div class="list-index" :style="template.isActive ? 'background: #409eff' : ''">
@@ -498,10 +514,11 @@
            </div>
            <el-image class="background" :src="template.previewImage" fit="contain" />
          </div>
          <el-empty v-if="templates.length==0" description="暂无数据" />
        </div>
        <div class="apply-all">
          <el-checkbox v-model="applyAllTemplate" :label="t('courseCenter.uploadAudio')" />
        </div>
<!--        <div class="apply-all">-->
<!--          <el-checkbox v-model="applyAllTemplate" :label="t('courseCenter.uploadAudio')" />-->
<!--        </div>-->
      </div>
      <!-- 背景设置 -->
      <div class="template-box template-right" v-if="showHeadImageTool">
@@ -751,10 +768,25 @@
    itemValue: '2'
  }
]
const tabs4 = [
  {
    itemName: t('我的'),
    itemValue: '2'
  },
  {
    itemName: t('模板库'),
    itemValue: '1'
  }
]
const tabs4ActiveNum = ref('2')
const tabs1Click = (item) => {
  tabs1ActiveNum.value = item.itemValue
  getList()
}
const tabs4Click = (item) => {
  tabs4ActiveNum.value = item.itemValue
  queryParams1.zg=tabs4ActiveNum.value
  getList1()
}
const tabs2Click = (item) => {
@@ -780,18 +812,18 @@
    activeUrl: userActive,
    isActive: false
  },
  {
    name: t('courseCenter.background'),
    url: bg,
    activeUrl: bgActive,
    isActive: false
  },
  {
    name: t('courseCenter.pictureInPicture'),
    url: innerPicture,
    activeUrl: innerPictureActive,
    isActive: false
  }
  // {
  //   name: t('courseCenter.background'),
  //   url: bg,
  //   activeUrl: bgActive,
  //   isActive: false
  // },
  // {
  //   name: t('courseCenter.pictureInPicture'),
  //   url: innerPicture,
  //   activeUrl: innerPictureActive,
  //   isActive: false
  // }
])
const showHeadImageTool = ref(false)
@@ -828,8 +860,11 @@
  if (item.name == t('courseCenter.digitalPeople')) {
    tabs1ActiveNum.value = '0'
    getList()
  }else if (item.name == t('courseCenter.template')) {
    tabs4ActiveNum.value = '2'
    queryParams1.zg=tabs4ActiveNum.value
    getList1()
  }
  showHeadImageTool.value = item.name === t('courseCenter.background')
  showTemplateTool.value = item.name === t('courseCenter.template')
  showDigitalHumanTool.value = item.name === t('courseCenter.digitalPeople')
@@ -1187,7 +1222,11 @@
  gender: '',
  posture: ''
})
const queryParams1 = reactive({
  pageNo: 1,
  pageSize: 100,
  zg:''
})
const selectHost = ref(null)
const getList = async () => {
@@ -1198,16 +1237,6 @@
    queryParams.posture = tabs3ActiveNum.value
    queryParams.status = 0
    let data = await pptTemplateApi.pageList(queryParams)
    if (data.list.length == 0) {
      queryParams.type = tabs1ActiveNum.value == '0' ? '1' : '0'
      tabs1ActiveNum.value = queryParams.type
      data = await pptTemplateApi.pageList(queryParams)
      if (data.list.length == 0) {
        message.error('没有有效的数字人,请联系管理员')
        return
      }
    }
    data.list.forEach((item) => {
      item.isActive = false
    })
@@ -1858,9 +1887,22 @@
    uploadFileObj.size = pageInfo ? pageInfo.docInfo.fileSize : ''
  }
}
const getList1 = async () => {
  const data = await TemplateApi.getTemplatePage(queryParams1)
  if (data) {
    TEMPLATE_PRESETS.value = data.list.map((item) => ({
      ...item,
      showBackground: item.showBackground === 1,
      showDigitalHuman: item.showDigitalHuman === 1,
      showPpt: item.showPpt === 1
    }))
    templates.value = TEMPLATE_PRESETS.value.map((template) => cloneDeep(template))
    selectTemplate.value = cloneDeep(templates.value[0])
  }
}
onMounted(async () => {
  let data = await TemplateApi.getTemplatePage(queryParams)
  let data = await TemplateApi.getTemplatePage(queryParams1)
  TEMPLATE_PRESETS.value = data.list.map((item) => ({
    ...item,
    showBackground: item.showBackground === 1,
@@ -2175,14 +2217,14 @@
      border-bottom: 1px solid #ebeef5;
      .tabs-item {
        width: 30px;
        width: 50px;
        font-size: 14px;
        text-align: center;
        cursor: pointer;
        span {
          display: block;
          width: 30px;
          width: 50px;
          height: 2px;
          margin-top: 5px;
          background: #409eff;
@@ -2328,7 +2370,7 @@
    z-index: 1;
    width: 100%;
    height: 100%;
    background-color: #f0f1fa;
    //background-color: #f0f1fa;
  }
  .template-tool {
easegen-front/src/views/dialogue/index.vue
@@ -1,43 +1,69 @@
<template>
<div>
  <div class="remote-container"></div>
</div>
  <div>
    <div class="remote-container" classNamev>
    </div>
  </div>
</template>
<script>
import DUIX from 'duix-guiji-light'
import {getDuixSign} from "../../api/dialogue";
import * as pptTemplateApi from "../../api/pptTemplate";
import DUIX from 'duix-guiji-light';
import {getDuixSign} from "../../api/dialogue/index.ts";
export default {
  name: "index"
}
const tempConversationId ='dev-'+ Math.random().toString(36).substring(2, 11);
const duix = new DUIX()
  name: "index",
  mounted() {
    this.$nextTick(() => {
      this.initDuix();
    });
  },
  methods: {
  getDuixSign().then(res => {
    if (res.code === 200) {
      duix.init({
        sign: res.data.sign,
        containerLable: '.remote-container',
        conversationId: tempConversationId,
      })
    }
  })
duix.on('getDuixSign', () => {
  // start session
  duix.start({
    conversationId: tempConversationId,
    openAsr: true
  }).then(res => {
    console.info(res)
  })
})
    async initDuix() {
      // 1. 检查容器是否存在
      const container = document.querySelector('.remote-container');
      if (!container) {
        console.error("错误:未找到 .remote-container 元素");
        return;
      }
      // 2. 获取 Token
      let token;
      try {
        const res = await getDuixSign();
        token = res.data?.sign || res.sign || res;
        if (!token) throw new Error("Token 为空");
      } catch (err) {
        console.error("获取签名失败:", err);
        return;
      }
      // 3. 初始化 DUIX
      const duix = new DUIX();
      const conversationId = 'dev-'+ Math.random().toString(36).substring(2, 11);;
      try {
        await duix.init({
          sign: token,
          containerLable: '.remote-container', // 注意:可能是 containerLabel(检查拼写)
          conversationId: conversationId,
        });
        // 4. 监听事件
        duix.on('getDuixSign', () => {
          duix.start({conversationId, openAsr: true})
            .then(() => console.log("DUIX 启动成功"))
            .catch(err => console.error("DUIX 启动失败:", err));
        });
      } catch (initErr) {
        console.error("DUIX 初始化失败:", initErr);
      }
    },
  },
};
</script>
<style scoped>
.remote-container{
.remote-container {
  width: 500px;
  height: 500px;
  border: 1px solid red; /* 调试时高亮容器 */
}
</style>
easegen-front/src/views/digitalcourse/digitalhumans/LookDigitalHumansForm.vue
@@ -35,15 +35,15 @@
        </el-form-item>
        <el-form-item label="背景样式" prop="isTransparent">
          <el-select v-model="formData.isTransparent" placeholder="请选择是否去除背景">
            <el-option value="1" label="透明背景"/>
            <el-option value="2" label="绿幕背景"/>
            <el-option :value="1" label="透明背景"/>
            <el-option :value="2" label="绿幕背景"/>
          </el-select>
        </el-form-item>
        <el-form-item v-if="formData.useModel == 1" :label="t('digitalhumans.picture')" prop="pictureUrl">
          <UploadImg v-if="formData" v-model="formData.fixPictureUrl" />
          <UploadImg v-else v-model="formData.pictureUrl" />
        </el-form-item>
        <!-- <el-form-item v-if="formData.useModel == 2" :label="t('digitalhumans.video')" prop="videoUrl"> -->
        <el-form-item v-if="false" :label="t('digitalhumans.video')" prop="videoUrl">
          <!-- 原本自带的视频上传 -->
@@ -85,8 +85,9 @@
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="submitForm" type="primary" :disabled="formLoading" :loading="isUploading" >{{t('common.ok')}}</el-button>
        <el-button @click="dialogVisible = false">{{t('common.cancel')}}</el-button>
        <el-button @click="submitForm" type="primary" :disabled="formLoading" :loading="isUploading" v-if="formType=='updata'">{{t('common.ok')}}</el-button>
        <el-button @click="dialogVisible = false" v-if="formType=='updata'">{{t('common.cancel')}}</el-button>
        <el-button @click="dialogVisible = false" v-if="formType=='detail'">关闭</el-button>
      </template>
    </Dialog>
  </template>
@@ -100,10 +101,10 @@
  import { useUpload } from '@/components/UploadFile/src/useUpload'
  import { el } from 'element-plus/es/locale';
  import { any } from 'vue-types';
  const { t } = useI18n() // 国际化
  const message = useMessage() // 消息弹窗
  const { uploadUrl, httpRequest } = useUpload() //上传方法
  const dialogVisible = ref(false) // 弹窗的是否展示
  const dialogTitle = ref('') // 弹窗的标题
@@ -128,10 +129,10 @@
    status: undefined,
    isTransparent: undefined,
  })
  // 当前是否正在上传视频
  const isUploading = ref(false)
  const videoProperty = {
    videoUrl: '',
    posterUrl: '',
@@ -143,7 +144,7 @@
      height: 300
    }
  } as DiyComponent<VideoPlayerProperty>
  watch(()=> formData.value.videoUrl,(newVal,oldValue)=>{
    if (newVal && newVal.length > 0){
      videoProperty.videoUrl = formData.value.fixVideoUrl || newVal
@@ -164,12 +165,12 @@
    videoUrl: [{ required: true, message: '视频不能为空', trigger: 'blur' }]
  })
  const formRef = ref() // 表单 Ref
  const StartCes = () => {
    console.log( " ----- 开始 ----- " )
    isUploading.value = true
  }
  const End = (res)=>{
    const FileObject = {
      file:res
@@ -180,9 +181,9 @@
    } ).finally( res => {
      isUploading.value = false
    } )
  }
  /** 打开弹窗 */
  const open = async (type: string, id?: number) => {
    dialogVisible.value = true
@@ -202,7 +203,7 @@
    }
  }
  defineExpose({ open }) // 提供 open 方法,用于打开弹窗
  /** 提交表单 */
  const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
  const submitForm = async () => {
@@ -226,7 +227,7 @@
      formLoading.value = false
    }
  }
  /** 重置表单 */
  const resetForm = () => {
    formData.value = {
@@ -254,9 +255,9 @@
      formData.value.videoUrl = response.data;
    }
  };
  // 修改默认的数字人视频模式为视频
  const InitHumMODEL = ()=>{
    let ModelList = getIntDictOptions( DICT_TYPE.USE_MODEL )
    for (let index = 0; index < ModelList.length; index++) {
@@ -266,6 +267,5 @@
      }
    }
  }
  </script>
easegen-front/src/views/digitalcourse/digitalhumans/index.vue
@@ -161,6 +161,23 @@
          >
            {{t('digitalhumans.handle')}}
          </el-button>
          <el-button
            link
            type="primary"
            @click="OpenLookformRef('detail', scope.row.id)"
            v-hasPermi="['digitalcourse:digital-humans:delete']"
          >
            {{t('digitalhumans.view')}}
          </el-button>
          <el-button
            link
            type="primary"
            @click="OpenLookformRef('updata', scope.row.id)"
            v-hasPermi="['digitalcourse:digital-humans:delete']"
          >
            修改
          </el-button>
          <el-button
            :disabled="scope.row.status == 3 || scope.row.status == 6"
            link
@@ -169,14 +186,6 @@
            v-hasPermi="['digitalcourse:digital-humans:delete']"
          >
            {{ t('action.del') }}
          </el-button>
          <el-button
            link
            type="primary"
            @click="OpenLookformRef('detail', scope.row.id)"
            v-hasPermi="['digitalcourse:digital-humans:delete']"
          >
            {{t('digitalhumans.view')}}
          </el-button>
        </template>
      </el-table-column>
easegen-front/src/views/digitalcourse/template/TemplateForm.vue
@@ -96,7 +96,6 @@
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="12">
          <el-form-item :label="t('template.digitalPeopleWidth')" prop="humanW">
            <el-input type="number" disabled v-model="formData.humanW" :placeholder="t('common.inputText') + t('template.digitalPeopleWidth')" />
@@ -119,8 +118,16 @@
            <el-input type="number" v-model="formData.humanY" :placeholder="t('common.inputText') + t('template.leftPositionDigitalPeople')" />
          </el-form-item>
        </el-col>
      </el-row>
      <el-row v-if="ishasAdminRole==true">
        <el-col :span="12">
          <el-form-item label="模板类型" prop="zg">
            <el-select v-model="formData.zg">
              <el-option label="公用模板" :value="1">公用模板</el-option>
              <el-option label="我的模板" :value="2">我的模板</el-option>
            </el-select>
          </el-form-item>
        </el-col>
      </el-row>
      <el-row>
        <el-col :span="12">
@@ -135,13 +142,6 @@
        </el-col>
      </el-row>
    </el-form>
    <template #footer>
      <el-button @click="submitForm" type="primary" :disabled="formLoading">{{ t('common.ok') }}</el-button>
@@ -152,6 +152,7 @@
<script setup lang="ts">
import { TemplateApi, TemplateVO } from '@/api/digitalcourse/template'
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
import {getUserProfile} from "@/api/system/user/profile";
/** 模板 表单 */
defineOptions({ name: 'TemplateForm' })
@@ -192,15 +193,27 @@
  humanH: [{ required: true, message: t('template.digitalPeopleHeight') + t('common.notEmpty'), trigger: 'blur' }],
  humanX: [{ required: true, message: t('template.topPositionDigitalPeople') + t('common.notEmpty'), trigger: 'blur' }],
  humanY: [{ required: true, message: t('template.leftPositionDigitalPeople') + t('common.notEmpty'), trigger: 'blur' }],
  zg: [{ required: true, message: '模板类型', trigger: 'blur' }],
})
const formRef = ref() // 表单 Ref
let ishasAdminRole = ref(false)
let userInfo = ref()
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
  dialogVisible.value = true
  dialogTitle.value = t('action.' + type)
  formType.value = type
  //获取当前登录人的信息
   userInfo.value = await getUserProfile()
  let hasAdminRole = userInfo.value.roles.some(role => role.name === '数字人管理员')
  console.log(hasAdminRole)
  resetForm()
  if (hasAdminRole) {
    ishasAdminRole=true
  }else {
    ishasAdminRole=false
    formData.value.zg = '2'
  }
  // 修改时,设置数据
  if (id) {
    formLoading.value = true
@@ -261,13 +274,14 @@
    showPpt: undefined,
    pptW: undefined,
    pptH: undefined,
    pptX: undefined,
    pptY: undefined,
    bgImage: undefined,
    pptX: '40',
    pptY: '77',
    humanW: undefined,
    humanH: undefined,
    humanX: undefined,
    humanY: undefined,
    bgImage: undefined,
    humanX: '349',
    humanY: '92',
    zg:1,
  }
  formRef.value?.resetFields()
}
easegen-front/src/views/digitalcourse/template/index.vue
@@ -45,87 +45,180 @@
  <!-- 列表 -->
  <ContentWrap>
    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
      <el-table-column :label="t('table.index')" align="center" type='index' width="60"/>
      <el-table-column :label="t('template.name')" align="center" prop="templateName" />
      <el-table-column :label="t('template.isShowBackground')" align="center" prop="showBackground" >
        <template #default="scope">
          <dict-tag :type="DICT_TYPE.IS_OR_NOT" :value="scope.row.showBackground" />
        </template>
      </el-table-column>
      <el-table-column :label="t('template.isShowDigitalPeople')" align="center" prop="showDigitalHuman" >
        <template #default="scope">
          <dict-tag :type="DICT_TYPE.IS_OR_NOT" :value="scope.row.showDigitalHuman" />
        </template>
      </el-table-column>
      <el-table-column :label="t('template.isShowPPt')" align="center" prop="showPpt" >
        <template #default="scope">
          <dict-tag :type="DICT_TYPE.IS_OR_NOT" :value="scope.row.showPpt" />
        </template>
      </el-table-column>
<!--      <el-table-column label="ppt宽" align="center" prop="pptW" />
      <el-table-column label="ppt高" align="center" prop="pptH" />
      <el-table-column label="ppt距离顶部位置" align="center" prop="pptX" />
      <el-table-column label="ppt距离左侧位置" align="center" prop="pptY" />
      <el-table-column label="数字人宽" align="center" prop="humanW" />
      <el-table-column label="数字人高" align="center" prop="humanH" />
      <el-table-column label="数字人距离顶部位置" align="center" prop="humanX" />
      <el-table-column label="数字人距离左侧位置" align="center" prop="humanY" />-->
      <el-table-column label="背景图片" align="center" prop="bgImage">
        <template #default="scope">
          <el-image
            :src="scope.row.bgImage"
            :preview-src-list="[scope.row.bgImage]"
            fit="cover"
            preview-teleported
    <el-tabs v-model="activeName" class="demo-tabs" @click="iszg">
      <el-tab-pane label="我的模板" name="first">
        <el-table :default-sort="{ prop: 'createTime', order: 'descending' }" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
          <el-table-column :label="t('table.index')" align="center" type='index' width="60"/>
          <el-table-column :label="t('template.name')" align="center" prop="templateName" />
          <el-table-column :label="t('template.isShowBackground')" align="center" prop="showBackground" >
            <template #default="scope">
              <dict-tag :type="DICT_TYPE.IS_OR_NOT" :value="scope.row.showBackground" />
            </template>
          </el-table-column>
          <el-table-column :label="t('template.isShowDigitalPeople')" align="center" prop="showDigitalHuman" >
            <template #default="scope">
              <dict-tag :type="DICT_TYPE.IS_OR_NOT" :value="scope.row.showDigitalHuman" />
            </template>
          </el-table-column>
          <el-table-column :label="t('template.isShowPPt')" align="center" prop="showPpt" >
            <template #default="scope">
              <dict-tag :type="DICT_TYPE.IS_OR_NOT" :value="scope.row.showPpt" />
            </template>
          </el-table-column>
          <!--      <el-table-column label="ppt宽" align="center" prop="pptW" />
                <el-table-column label="ppt高" align="center" prop="pptH" />
                <el-table-column label="ppt距离顶部位置" align="center" prop="pptX" />
                <el-table-column label="ppt距离左侧位置" align="center" prop="pptY" />
                <el-table-column label="数字人宽" align="center" prop="humanW" />
                <el-table-column label="数字人高" align="center" prop="humanH" />
                <el-table-column label="数字人距离顶部位置" align="center" prop="humanX" />
                <el-table-column label="数字人距离左侧位置" align="center" prop="humanY" />-->
          <el-table-column label="背景图片" align="center" prop="bgImage">
            <template #default="scope">
              <el-image
                :src="scope.row.bgImage"
                :preview-src-list="[scope.row.bgImage]"
                fit="cover"
                preview-teleported
              />
            </template>
          </el-table-column>
          <el-table-column label="预览图片" align="center" prop="previewImage">
            <template #default="scope">
              <el-image
                :src="scope.row.previewImage"
                :preview-src-list="[scope.row.previewImage]"
                fit="cover"
                preview-teleported
              />
            </template>
          </el-table-column>
          <el-table-column
            :label="t('table.createTime')"
            align="center"
            prop="createTime"
            sortable
            :formatter="dateFormatter"
            width="180px"
          />
        </template>
      </el-table-column>
      <el-table-column label="预览图片" align="center" prop="previewImage">
        <template #default="scope">
          <el-image
            :src="scope.row.previewImage"
            :preview-src-list="[scope.row.previewImage]"
            fit="cover"
            preview-teleported
          <el-table-column label="创建人"  align="center" prop="creator" />
          <el-table-column :label="t('table.action')" align="center" min-width="120px">
            <template #default="scope">
              <el-button
                link
                type="primary"
                @click="openForm('update', scope.row.id)"
                v-hasPermi="['digitalcourse:template:update']"
              >
                {{ t('action.edit') }}
              </el-button>
              <el-button
                link
                type="danger"
                @click="handleDelete(scope.row.id)"
                v-hasPermi="['digitalcourse:template:delete']"
              >
                {{ t('action.del') }}
              </el-button>
            </template>
          </el-table-column>
        </el-table>
        <!-- 分页 -->
        <Pagination
          :total="total"
          v-model:page="queryParams.pageNo"
          v-model:limit="queryParams.pageSize"
          @pagination="getList"
        />
      </el-tab-pane>
      <el-tab-pane label="模板库模板" name="second">
        <el-table :default-sort="{ prop: 'createTime', order: 'descending' }" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
          <el-table-column :label="t('table.index')" align="center" type='index' width="60"/>
          <el-table-column :label="t('template.name')" align="center" prop="templateName" />
          <el-table-column :label="t('template.isShowBackground')" align="center" prop="showBackground" >
            <template #default="scope">
              <dict-tag :type="DICT_TYPE.IS_OR_NOT" :value="scope.row.showBackground" />
            </template>
          </el-table-column>
          <el-table-column :label="t('template.isShowDigitalPeople')" align="center" prop="showDigitalHuman" >
            <template #default="scope">
              <dict-tag :type="DICT_TYPE.IS_OR_NOT" :value="scope.row.showDigitalHuman" />
            </template>
          </el-table-column>
          <el-table-column :label="t('template.isShowPPt')" align="center" prop="showPpt" >
            <template #default="scope">
              <dict-tag :type="DICT_TYPE.IS_OR_NOT" :value="scope.row.showPpt" />
            </template>
          </el-table-column>
          <!--      <el-table-column label="ppt宽" align="center" prop="pptW" />
                <el-table-column label="ppt高" align="center" prop="pptH" />
                <el-table-column label="ppt距离顶部位置" align="center" prop="pptX" />
                <el-table-column label="ppt距离左侧位置" align="center" prop="pptY" />
                <el-table-column label="数字人宽" align="center" prop="humanW" />
                <el-table-column label="数字人高" align="center" prop="humanH" />
                <el-table-column label="数字人距离顶部位置" align="center" prop="humanX" />
                <el-table-column label="数字人距离左侧位置" align="center" prop="humanY" />-->
          <el-table-column label="背景图片" align="center" prop="bgImage">
            <template #default="scope">
              <el-image
                :src="scope.row.bgImage"
                :preview-src-list="[scope.row.bgImage]"
                fit="cover"
                preview-teleported
              />
            </template>
          </el-table-column>
          <el-table-column label="预览图片" align="center" prop="previewImage">
            <template #default="scope">
              <el-image
                :src="scope.row.previewImage"
                :preview-src-list="[scope.row.previewImage]"
                fit="cover"
                preview-teleported
              />
            </template>
          </el-table-column>
          <el-table-column
            :label="t('table.createTime')"
            align="center"
            prop="createTime"
            sortable
            :formatter="dateFormatter"
            width="180px"
          />
        </template>
      </el-table-column>
      <el-table-column
        :label="t('table.createTime')"
        align="center"
        prop="createTime"
        :formatter="dateFormatter"
        width="180px"
      />
      <el-table-column :label="t('table.action')" align="center" min-width="120px">
        <template #default="scope">
          <el-button
            link
            type="primary"
            @click="openForm('update', scope.row.id)"
            v-hasPermi="['digitalcourse:template:update']"
          >
            {{ t('action.edit') }}
          </el-button>
          <el-button
            link
            type="danger"
            @click="handleDelete(scope.row.id)"
            v-hasPermi="['digitalcourse:template:delete']"
          >
            {{ t('action.del') }}
          </el-button>
        </template>
      </el-table-column>
    </el-table>
    <!-- 分页 -->
    <Pagination
      :total="total"
      v-model:page="queryParams.pageNo"
      v-model:limit="queryParams.pageSize"
      @pagination="getList"
    />
          <el-table-column label="创建人"  align="center" prop="creator" />
          <el-table-column :label="t('table.action')" align="center" min-width="120px" v-if="hasAdminRole">
            <template #default="scope">
              <el-button
                link
                type="primary"
                @click="openForm('update', scope.row.id)"
                v-hasPermi="['digitalcourse:template:update']"
              >
                {{ t('action.edit') }}
              </el-button>
              <el-button
                link
                type="danger"
                @click="handleDelete(scope.row.id)"
                v-hasPermi="['digitalcourse:template:delete']"
              >
                {{ t('action.del') }}
              </el-button>
            </template>
          </el-table-column>
        </el-table>
        <!-- 分页 -->
        <Pagination
          :total="total"
          v-model:page="queryParams.pageNo"
          v-model:limit="queryParams.pageSize"
          @pagination="getList"
        />
      </el-tab-pane>
    </el-tabs>
  </ContentWrap>
  <!-- 表单弹窗:添加/修改 -->
@@ -138,13 +231,14 @@
import { TemplateApi, TemplateVO } from '@/api/digitalcourse/template'
import TemplateForm from './TemplateForm.vue'
import {DICT_TYPE} from "@/utils/dict";
import type { TabsPaneContext } from 'element-plus'
import {getUserProfile} from "@/api/system/user/profile";
/** 模板 列表 */
defineOptions({ name: 'Template' })
const message = useMessage() // 消息弹窗
const { t } = useI18n() // 国际化
const activeName = ref('first')
const loading = ref(true) // 列表的加载中
const list = ref<TemplateVO[]>([]) // 列表的数据
const total = ref(0) // 列表的总页数
@@ -164,13 +258,18 @@
  humanY: undefined,
  bgImage: undefined,
  createTime: [],
  zg: 2
})
const queryFormRef = ref() // 搜索的表单
const exportLoading = ref(false) // 导出的加载中
let userInfo = ref()
let hasAdminRole = ref(false)
/** 查询列表 */
const getList = async () => {
  loading.value = true
  userInfo.value = await getUserProfile()
   hasAdminRole = userInfo.value.roles.some(role => role.name === '数字人管理员')
  try {
    const data = await TemplateApi.getTemplatePage(queryParams)
    list.value = data.list
@@ -189,6 +288,7 @@
/** 重置按钮操作 */
const resetQuery = () => {
  queryFormRef.value.resetFields()
  queryParams.zg = '2'
  handleQuery()
}
@@ -225,6 +325,16 @@
    exportLoading.value = false
  }
}
const iszg = () => {
  console.log(activeName)
  if (activeName.value == 'first') {
    queryParams.zg = 2
    getList()
  }else if (activeName.value == 'second') {
    queryParams.zg = 1
    getList()
  }
}
/** 初始化 **/
onMounted(() => {
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/controller/admin/digitalhumans/vo/DigitalHumansRespVO.java
@@ -104,4 +104,5 @@
    //过期时间
    private Date expireDate;
}
    private Integer isTransparent;
}
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/controller/admin/template/TemplateController.java
@@ -92,4 +92,4 @@
                        BeanUtils.toBean(list, TemplateRespVO.class));
    }
}
}
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/controller/admin/template/vo/TemplatePageReqVO.java
@@ -64,4 +64,5 @@
    @Schema(description = "模板名称")
    private String templateName;;
}
    private Integer zg;
}
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/controller/admin/template/vo/TemplateRespVO.java
@@ -76,4 +76,6 @@
    @Schema(description = "模板尺寸")
    private String templateSize;
}
    private Integer zg;
    private String creator;
}
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/controller/admin/template/vo/TemplateSaveReqVO.java
@@ -57,8 +57,8 @@
    @NotNull(message = "数字人距离左侧位置不能为空")
    private BigDecimal humanY;
    @Schema(description = "背景图片", requiredMode = Schema.RequiredMode.REQUIRED)
    @NotEmpty(message = "背景图片不能为空")
    //@Schema(description = "背景图片", requiredMode = Schema.RequiredMode.REQUIRED)
    //@NotEmpty(message = "背景图片不能为空")
    private String bgImage;
    @Schema(description = "效果图")
@@ -70,4 +70,5 @@
    @Schema(description = "模板尺寸")
    private String templateSize;
}
    private Integer zg;
}
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/dal/dataobject/template/TemplateDO.java
@@ -86,4 +86,5 @@
    // 模板尺寸
    private String templateSize;
}
    private Integer zg;
}
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/dal/mysql/template/TemplateMapper.java
@@ -5,6 +5,7 @@
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.yudao.module.digitalcourse.dal.dataobject.template.TemplateDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.digitalcourse.controller.admin.template.vo.*;
@@ -18,7 +19,8 @@
public interface TemplateMapper extends BaseMapperX<TemplateDO> {
    default PageResult<TemplateDO> selectPage(TemplatePageReqVO reqVO) {
        return selectPage(reqVO, new LambdaQueryWrapperX<TemplateDO>()
        Long loginUserId = WebFrameworkUtils.getLoginUserId();
        LambdaQueryWrapperX<TemplateDO> wrapper = new LambdaQueryWrapperX<TemplateDO>()
                .eqIfPresent(TemplateDO::getShowBackground, reqVO.getShowBackground())
                .eqIfPresent(TemplateDO::getShowDigitalHuman, reqVO.getShowDigitalHuman())
                .eqIfPresent(TemplateDO::getShowPpt, reqVO.getShowPpt())
@@ -31,8 +33,34 @@
                .eqIfPresent(TemplateDO::getHumanX, reqVO.getHumanX())
                .eqIfPresent(TemplateDO::getHumanY, reqVO.getHumanY())
                .eqIfPresent(TemplateDO::getBgImage, reqVO.getBgImage())
                .betweenIfPresent(TemplateDO::getCreateTime, reqVO.getCreateTime())
                .orderByAsc(TemplateDO::getId));
                .betweenIfPresent(TemplateDO::getCreateTime, reqVO.getCreateTime());
                Integer zgParam = reqVO.getZg();
                if (loginUserId != 1) {
                    if (zgParam != null) {
                        if (zgParam == 1) {
                            wrapper.eq(TemplateDO::getZg, 1);
                        } else if (zgParam == 2) {
                            wrapper.eq(TemplateDO::getZg, 2).eq(TemplateDO::getCreator, loginUserId);
                        }
                    } else {
                        // zg 未传,查 zg = 1 或 (zg = 2 且 creator = 自己)
                        wrapper.and(w -> w.eq(TemplateDO::getZg, 1)
                                .or()
                                .eq(TemplateDO::getZg, 2).eq(TemplateDO::getCreator, loginUserId));
                    }
                }else {
                    if (zgParam != null) {
                        if (zgParam == 1) {
                            wrapper.eq(TemplateDO::getZg, 1);
                        } else if (zgParam == 2) {
                            wrapper.eq(TemplateDO::getZg, 2);
                        }
                    }
                }
                wrapper.orderByAsc(TemplateDO::getId);
        return selectPage(reqVO, wrapper);
    }
}
}
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/coursemedia/CourseMediaServiceUtil.java
@@ -170,10 +170,10 @@
                // 当没有人像时,视频放在 cover 的下层
                builder = new ProcessBuilder(
                        "ffmpeg",
                        "-i", cover1,     // 背景图 1
                        "-i", substring1, // 视频(含音频)
                        "-i", cover1,     // 背景图 2
                        "-i", cover,      // PPT 内容
                        "-loop", "1", "-i", cover1,     // 背景图1(动态持续)
                        "-i", substring1,               // 视频(含音频)
                        "-loop", "1", "-i", cover1,     // 背景图2(动态持续)
                        "-loop", "1", "-i", cover,      // PPT 内容(动态持续)
                        "-filter_complex",
                        "[0:v]scale=" + Math.round(scene.getBackground().getWidth()) + ":" + Math.round(scene.getBackground().getHeight()) + "[bg1];" +
                                "[1:v]scale=" + Math.round(scene.getComponents().get(0).getWidth()) + ":" + Math.round(scene.getComponents().get(0).getHeight()) + "[v1];" +
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/digitalhumans/DigitalHumansServiceImpl.java
@@ -137,7 +137,7 @@
    }
    @Override
    public PageResult<DigitalHumansDO> getDigitalHumansPage(DigitalHumansPageReqVO pageReqVO) {
        if(pageReqVO.getType()==1){
        if(pageReqVO.getType() != null && pageReqVO.getType()==1){
            //查询非公共数字人,只能查询自己的,公共数字人,可以查询所有的
            if (WebFrameworkUtils.getLoginUserId() != 1) pageReqVO.setCreator(String.valueOf(WebFrameworkUtils.getLoginUserId()));
        }
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/service/template/TemplateServiceImpl.java
@@ -1,5 +1,8 @@
package cn.iocoder.yudao.module.digitalcourse.service.template;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
@@ -31,6 +34,10 @@
    @Override
    public Long createTemplate(TemplateSaveReqVO createReqVO) {
        Integer zg = createReqVO.getZg();
        if (zg != null && zg != 1) {
            createReqVO.setZg(2);
        }
        // 插入
        TemplateDO template = BeanUtils.toBean(createReqVO, TemplateDO.class);
        templateMapper.insert(template);
@@ -66,9 +73,16 @@
        return templateMapper.selectById(id);
    }
    @Autowired
    private AdminUserApi adminUserApi;
    @Override
    public PageResult<TemplateDO> getTemplatePage(TemplatePageReqVO pageReqVO) {
        return templateMapper.selectPage(pageReqVO);
        PageResult<TemplateDO> templateDOPageResult = templateMapper.selectPage(pageReqVO);
        for (TemplateDO templateDO : templateDOPageResult.getList()) {
            AdminUserRespDTO user = adminUserApi.getUser(Long.valueOf(templateDO.getCreator()));
            templateDO.setCreator(user.getNickname());
        }
        return templateDOPageResult;
    }
}
}
yudao-module-digitalcourse/yudao-module-digitalcourse-biz/src/main/java/cn/iocoder/yudao/module/digitalcourse/util/PPTUtil.java
@@ -193,7 +193,7 @@
        File pdfFile = File.createTempFile("ppt_to_pdf_"+tempFileName, ".pdf");
        String command;
        if (isWindows()) {
            command = String.format("\"E:\\LibreOffice\\LibreOffice\\program\\soffice.exe\" --headless --convert-to pdf --outdir %s %s", pdfFile.getParent(), pptFile.getAbsolutePath());
            command = String.format("\"C:\\Program Files\\LibreOffice\\program\\soffice.com\" --headless --convert-to pdf --outdir %s %s", pdfFile.getParent(), pptFile.getAbsolutePath());
        } else {
            command = String.format("libreoffice --headless --convert-to pdf --outdir %s %s", pdfFile.getParent(), pptFile.getAbsolutePath());
        }