mirror of
				https://gitee.com/hhyykk/ipms-sjy-ui.git
				synced 2025-11-04 20:28:45 +08:00 
			
		
		
		
	
							
								
								
									
										
											BIN
										
									
								
								.image/common/ai-feature.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.image/common/ai-feature.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 21 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								.image/common/ai-preview.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								.image/common/ai-preview.gif
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 348 KiB  | 
							
								
								
									
										14
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								README.md
									
									
									
									
									
								
							@@ -191,26 +191,24 @@ ps:核心功能已经实现,正在对接微信小程序中...
 | 
			
		||||
 | 
			
		||||
### 商城系统
 | 
			
		||||
 | 
			
		||||
演示地址:<https://doc.iocoder.cn/mall-preview/>
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
_前端基于 crmeb uniapp 经过授权重构,优化代码实现,接入芋道快速开发平台_
 | 
			
		||||
 | 
			
		||||
演示地址:<https://doc.iocoder.cn/mall-preview/>
 | 
			
		||||
 | 
			
		||||
### ERP 系统
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
演示地址:<https://doc.iocoder.cn/erp-preview/>
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
### CRM 系统
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
演示地址:<https://doc.iocoder.cn/crm-preview/>
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
## 🐷 演示图
 | 
			
		||||
 | 
			
		||||
### 系统功能
 | 
			
		||||
 
 | 
			
		||||
@@ -56,6 +56,10 @@ export const ImageApi = {
 | 
			
		||||
  getImagePageMy: async (params: PageParam) => {
 | 
			
		||||
    return await request.get({ url: `/ai/image/my-page`, params })
 | 
			
		||||
  },
 | 
			
		||||
  // 获取公开的绘图记录
 | 
			
		||||
  getImagePagePublic: async (params: PageParam) => {
 | 
			
		||||
    return await request.get({ url: `/ai/image/public-page`, params })
 | 
			
		||||
  },
 | 
			
		||||
  // 获取【我的】绘图记录
 | 
			
		||||
  getImageMy: async (id: number) => {
 | 
			
		||||
    return await request.get({ url: `/ai/image/get-my?id=${id}` })
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										85
									
								
								src/api/ai/write/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/api/ai/write/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
			
		||||
import { fetchEventSource } from '@microsoft/fetch-event-source'
 | 
			
		||||
 | 
			
		||||
import { getAccessToken } from '@/utils/auth'
 | 
			
		||||
import { config } from '@/config/axios/config'
 | 
			
		||||
import { AiWriteTypeEnum } from '@/views/ai/utils/constants'
 | 
			
		||||
import request from '@/config/axios'
 | 
			
		||||
 | 
			
		||||
export interface WriteVO {
 | 
			
		||||
  type: AiWriteTypeEnum.WRITING | AiWriteTypeEnum.REPLY // 1:撰写 2:回复
 | 
			
		||||
  prompt: string // 写作内容提示 1。撰写 2回复
 | 
			
		||||
  originalContent: string // 原文
 | 
			
		||||
  length: number // 长度
 | 
			
		||||
  format: number // 格式
 | 
			
		||||
  tone: number // 语气
 | 
			
		||||
  language: number // 语言
 | 
			
		||||
  userId?: number // 用户编号
 | 
			
		||||
  platform?: string // 平台
 | 
			
		||||
  model?: string // 模型
 | 
			
		||||
  generatedContent?: string // 生成的内容
 | 
			
		||||
  errorMessage?: string // 错误信息
 | 
			
		||||
  createTime?: Date // 创建时间
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AiWritePageReqVO extends PageParam {
 | 
			
		||||
  userId?: number // 用户编号
 | 
			
		||||
  type?: AiWriteTypeEnum //  写作类型
 | 
			
		||||
  platform?: string // 平台
 | 
			
		||||
  createTime?: [string, string] // 创建时间
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AiWriteRespVo {
 | 
			
		||||
  id: number
 | 
			
		||||
  userId: number
 | 
			
		||||
  type: number
 | 
			
		||||
  platform: string
 | 
			
		||||
  model: string
 | 
			
		||||
  prompt: string
 | 
			
		||||
  generatedContent: string
 | 
			
		||||
  originalContent: string
 | 
			
		||||
  length: number
 | 
			
		||||
  format: number
 | 
			
		||||
  tone: number
 | 
			
		||||
  language: number
 | 
			
		||||
  errorMessage: string
 | 
			
		||||
  createTime: string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const WriteApi = {
 | 
			
		||||
  writeStream: ({
 | 
			
		||||
    data,
 | 
			
		||||
    onClose,
 | 
			
		||||
    onMessage,
 | 
			
		||||
    onError,
 | 
			
		||||
    ctrl
 | 
			
		||||
  }: {
 | 
			
		||||
    data: WriteVO
 | 
			
		||||
    onMessage?: (res: any) => void
 | 
			
		||||
    onError?: (...args: any[]) => void
 | 
			
		||||
    onClose?: (...args: any[]) => void
 | 
			
		||||
    ctrl: AbortController
 | 
			
		||||
  }) => {
 | 
			
		||||
    const token = getAccessToken()
 | 
			
		||||
    return fetchEventSource(`${config.base_url}/ai/write/generate-stream`, {
 | 
			
		||||
      method: 'post',
 | 
			
		||||
      headers: {
 | 
			
		||||
        'Content-Type': 'application/json',
 | 
			
		||||
        Authorization: `Bearer ${token}`
 | 
			
		||||
      },
 | 
			
		||||
      openWhenHidden: true,
 | 
			
		||||
      body: JSON.stringify(data),
 | 
			
		||||
      onmessage: onMessage,
 | 
			
		||||
      onerror: onError,
 | 
			
		||||
      onclose: onClose,
 | 
			
		||||
      signal: ctrl.signal
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
  // 获取写作列表
 | 
			
		||||
  getWritePage: (params: AiWritePageReqVO) => {
 | 
			
		||||
    return request.get<PageResult<AiWriteRespVo[]>>({ url: `/ai/write/page`, params })
 | 
			
		||||
  },
 | 
			
		||||
  // 删除写作
 | 
			
		||||
  deleteWrite(id: number) {
 | 
			
		||||
    return request.delete({ url: `/ai/write/delete`, params: { id } })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,65 +0,0 @@
 | 
			
		||||
import { fetchEventSource } from '@microsoft/fetch-event-source'
 | 
			
		||||
import request from '@/config/axios'
 | 
			
		||||
 | 
			
		||||
import { getAccessToken } from '@/utils/auth'
 | 
			
		||||
import { config } from '@/config/axios/config'
 | 
			
		||||
import { AiWriteTypeEnum } from '@/views/ai/utils/constants'
 | 
			
		||||
 | 
			
		||||
export interface WriteVO {
 | 
			
		||||
  type: AiWriteTypeEnum.WRITING | AiWriteTypeEnum.REPLY // 1:撰写 2:回复
 | 
			
		||||
  prompt: string // 写作内容提示 1。撰写 2回复
 | 
			
		||||
  originalContent: string // 原文
 | 
			
		||||
  length: number // 长度
 | 
			
		||||
  format: number // 格式
 | 
			
		||||
  tone: number // 语气
 | 
			
		||||
  language: number // 语言
 | 
			
		||||
  userId?: number // 用户编号
 | 
			
		||||
  platform?: string // 平台
 | 
			
		||||
  model?: string // 模型
 | 
			
		||||
  generatedContent?: string // 生成的内容
 | 
			
		||||
  errorMessage: string // 错误信息
 | 
			
		||||
  createTime?: Date // 创建时间
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO @hhero:搞成 WriteApi,类似 ConversationApi 一样。这样更有类的概念,后续引入某个 Api,然后调用它的方法就可以了。
 | 
			
		||||
export const writeStream = ({
 | 
			
		||||
  data,
 | 
			
		||||
  onClose,
 | 
			
		||||
  onMessage,
 | 
			
		||||
  onError,
 | 
			
		||||
  ctrl
 | 
			
		||||
}: {
 | 
			
		||||
  data: WriteVO
 | 
			
		||||
  onMessage?: (res: any) => void
 | 
			
		||||
  onError?: (...args: any[]) => void
 | 
			
		||||
  onClose?: (...args: any[]) => void
 | 
			
		||||
  ctrl: AbortController
 | 
			
		||||
}) => {
 | 
			
		||||
  const token = getAccessToken()
 | 
			
		||||
  return fetchEventSource(`${config.base_url}/ai/write/generate-stream`, {
 | 
			
		||||
    method: 'post',
 | 
			
		||||
    headers: {
 | 
			
		||||
      'Content-Type': 'application/json',
 | 
			
		||||
      Authorization: `Bearer ${token}`
 | 
			
		||||
    },
 | 
			
		||||
    openWhenHidden: true,
 | 
			
		||||
    body: JSON.stringify(data),
 | 
			
		||||
    onmessage: onMessage,
 | 
			
		||||
    onerror: onError,
 | 
			
		||||
    onclose: onClose,
 | 
			
		||||
    signal: ctrl.signal
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AI 写作 API
 | 
			
		||||
export const WriteApi = {
 | 
			
		||||
  // 查询AI 写作分页
 | 
			
		||||
  getWritePage: async (params: any) => {
 | 
			
		||||
    return await request.get({ url: `/ai/write/page`, params })
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // 删除AI 写作
 | 
			
		||||
  deleteWrite: async (id: number) => {
 | 
			
		||||
    return await request.delete({ url: `/ai/write/delete?id=` + id })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -36,7 +36,13 @@
 | 
			
		||||
      <el-text tag="b">平台</el-text>
 | 
			
		||||
    </div>
 | 
			
		||||
    <el-space wrap class="group-item-body">
 | 
			
		||||
      <el-select v-model="otherPlatform" placeholder="Select" size="large" class="!w-350px" @change="handlerPlatformChange">
 | 
			
		||||
      <el-select
 | 
			
		||||
        v-model="otherPlatform"
 | 
			
		||||
        placeholder="Select"
 | 
			
		||||
        size="large"
 | 
			
		||||
        class="!w-350px"
 | 
			
		||||
        @change="handlerPlatformChange"
 | 
			
		||||
      >
 | 
			
		||||
        <el-option
 | 
			
		||||
          v-for="item in OtherPlatformEnum"
 | 
			
		||||
          :key="item.key"
 | 
			
		||||
@@ -52,12 +58,7 @@
 | 
			
		||||
    </div>
 | 
			
		||||
    <el-space wrap class="group-item-body">
 | 
			
		||||
      <el-select v-model="model" placeholder="Select" size="large" class="!w-350px">
 | 
			
		||||
        <el-option
 | 
			
		||||
          v-for="item in models"
 | 
			
		||||
          :key="item.key"
 | 
			
		||||
          :label="item.name"
 | 
			
		||||
          :value="item.key"
 | 
			
		||||
        />
 | 
			
		||||
        <el-option v-for="item in models" :key="item.key" :label="item.name" :value="item.key" />
 | 
			
		||||
      </el-select>
 | 
			
		||||
    </el-space>
 | 
			
		||||
  </div>
 | 
			
		||||
@@ -77,12 +78,14 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import {ImageApi, ImageDrawReqVO, ImageVO} from '@/api/ai/image'
 | 
			
		||||
import { ImageApi, ImageDrawReqVO, ImageVO } from '@/api/ai/image'
 | 
			
		||||
import {
 | 
			
		||||
  AiPlatformEnum,
 | 
			
		||||
  ChatGlmModels,
 | 
			
		||||
  ImageHotWords,
 | 
			
		||||
  ImageModelVO,
 | 
			
		||||
  OtherPlatformEnum,
 | 
			
		||||
  QianFanModels,
 | 
			
		||||
  TongYiWanXiangModels
 | 
			
		||||
} from '@/views/ai/utils/constants'
 | 
			
		||||
 | 
			
		||||
@@ -96,10 +99,9 @@ const prompt = ref<string>('') // 提示词
 | 
			
		||||
const width = ref<number>(512) // 图片宽度
 | 
			
		||||
const height = ref<number>(512) // 图片高度
 | 
			
		||||
const otherPlatform = ref<string>(AiPlatformEnum.TONG_YI) // 平台
 | 
			
		||||
const models = ref<ImageModelVO[]>(TongYiWanXiangModels) // 模型
 | 
			
		||||
const models = ref<ImageModelVO[]>(TongYiWanXiangModels) // 模型  TongYiWanXiangModels、QianFanModels
 | 
			
		||||
const model = ref<string>(models.value[0].key) // 模型
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const emits = defineEmits(['onDrawStart', 'onDrawComplete']) // 定义 emits
 | 
			
		||||
 | 
			
		||||
/** 选择热词 */
 | 
			
		||||
@@ -131,9 +133,8 @@ const handleGenerateImage = async () => {
 | 
			
		||||
      prompt: prompt.value, // 提示词
 | 
			
		||||
      width: width.value, // 图片宽度
 | 
			
		||||
      height: height.value, // 图片高度
 | 
			
		||||
      options: {
 | 
			
		||||
      }
 | 
			
		||||
    } as ImageDrawReqVO
 | 
			
		||||
      options: {}
 | 
			
		||||
    } as unknown as ImageDrawReqVO
 | 
			
		||||
    await ImageApi.drawImage(form)
 | 
			
		||||
  } finally {
 | 
			
		||||
    // 回调
 | 
			
		||||
@@ -148,21 +149,24 @@ const settingValues = async (detail: ImageVO) => {
 | 
			
		||||
  prompt.value = detail.prompt
 | 
			
		||||
  width.value = detail.width
 | 
			
		||||
  height.value = detail.height
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 平台切换 */
 | 
			
		||||
const handlerPlatformChange = async (platform) => {
 | 
			
		||||
const handlerPlatformChange = async (platform: string) => {
 | 
			
		||||
  // 切换平台,切换模型、风格
 | 
			
		||||
  if (AiPlatformEnum.YI_YAN === platform) {
 | 
			
		||||
  if (AiPlatformEnum.TONG_YI === platform) {
 | 
			
		||||
    models.value = TongYiWanXiangModels
 | 
			
		||||
  } else if (AiPlatformEnum.YI_YAN === platform) {
 | 
			
		||||
    models.value = QianFanModels
 | 
			
		||||
  } else if (AiPlatformEnum.ZHI_PU === platform) {
 | 
			
		||||
    models.value = ChatGlmModels
 | 
			
		||||
  } else {
 | 
			
		||||
    models.value = []
 | 
			
		||||
  }
 | 
			
		||||
  // 切换平台,默认选择一个风格
 | 
			
		||||
  if (models.value.length > 0) {
 | 
			
		||||
    model.value = models.value[0].key
 | 
			
		||||
  } else  {
 | 
			
		||||
  } else {
 | 
			
		||||
    model.value = ''
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -62,7 +62,7 @@ const platformOptions = [
 | 
			
		||||
    value: AiPlatformEnum.STABLE_DIFFUSION
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    label: '其他',
 | 
			
		||||
    label: '其它',
 | 
			
		||||
    value: 'other'
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
@@ -88,6 +88,7 @@ const handleRegeneration = async (image: ImageVO) => {
 | 
			
		||||
  } else if (image.platform === AiPlatformEnum.STABLE_DIFFUSION) {
 | 
			
		||||
    stableDiffusionRef.value.settingValues(image)
 | 
			
		||||
  }
 | 
			
		||||
  // TODO @fan:貌似 other 重新设置不行?
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										41
									
								
								src/views/ai/image/square/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/views/ai/image/square/index.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="card-list">
 | 
			
		||||
    <div v-for="item in publicList" :key="item.id" class="card">
 | 
			
		||||
      <img :src="item.picUrl" class="img" />
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ImageApi, ImageVO } from '@/api/ai/image'
 | 
			
		||||
 | 
			
		||||
/** 属性 */
 | 
			
		||||
// TODO @fan:queryParams 里面搞分页哈。
 | 
			
		||||
const pageNo = ref<number>(1)
 | 
			
		||||
const pageSize = ref<number>(20)
 | 
			
		||||
const publicList = ref<ImageVO[]>([])
 | 
			
		||||
 | 
			
		||||
/** 获取数据 */
 | 
			
		||||
const getListData = async () => {
 | 
			
		||||
  const res = await ImageApi.getImagePagePublic({ pageNo: pageNo.value, pageSize: pageSize.value })
 | 
			
		||||
  publicList.value = res.list as ImageVO[]
 | 
			
		||||
  console.log('publicList.value', publicList.value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
onMounted(async () => {
 | 
			
		||||
  await getListData()
 | 
			
		||||
})
 | 
			
		||||
</script>
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.card-list {
 | 
			
		||||
  //display: flex;
 | 
			
		||||
  //flex-direction: column;
 | 
			
		||||
  column-count: 4;
 | 
			
		||||
  column-gap: 3px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.card {
 | 
			
		||||
  .img {
 | 
			
		||||
    width: 50%;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="flex h-1/1">
 | 
			
		||||
  <div class="flex ">
 | 
			
		||||
    <!-- 模式 -->
 | 
			
		||||
    <Mode class="flex-none" @generate-music="generateMusic"/>
 | 
			
		||||
    <!-- 音频列表 -->
 | 
			
		||||
@@ -13,7 +13,7 @@ import List from './list/index.vue'
 | 
			
		||||
 | 
			
		||||
defineOptions({ name: 'Index' })
 | 
			
		||||
 | 
			
		||||
const listRef = ref<{generateMusic: (...args) => void} | null>(null)
 | 
			
		||||
const listRef = ref<Nullable<{generateMusic: (...args) => void}>>(null)
 | 
			
		||||
 | 
			
		||||
function generateMusic (args: {formData: Recordable}) {
 | 
			
		||||
 unref(listRef)?.generateMusic(args.formData)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,68 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="h-72px bg-[var(--el-bg-color-overlay)] b-solid b-1 b-[var(--el-border-color)] b-l-none">播放器</div>
 | 
			
		||||
  <div class="flex items-center justify-between px-2 h-72px bg-[var(--el-bg-color-overlay)] b-solid b-1 b-[var(--el-border-color)] b-l-none">
 | 
			
		||||
    <!-- 歌曲信息 -->
 | 
			
		||||
    <div class="flex gap-[10px]">
 | 
			
		||||
      <el-image src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png" class="w-[45px]"/>
 | 
			
		||||
      <div>
 | 
			
		||||
        <div>我很好</div>
 | 
			
		||||
        <div class="text-[12px] text-gray-400">刘大壮</div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
      
 | 
			
		||||
    <!-- 音频controls -->
 | 
			
		||||
    <div class="flex gap-[12px] items-center">
 | 
			
		||||
      <Icon icon="majesticons:back-circle" :size="20" class="text-gray-300 cursor-pointer"/>
 | 
			
		||||
      <Icon :icon="audioProps.paused ? 'mdi:arrow-right-drop-circle' : 'solar:pause-circle-bold'" :size="30" class=" cursor-pointer" @click="toggleStatus('paused')"/>
 | 
			
		||||
      <Icon icon="majesticons:next-circle" :size="20" class="text-gray-300 cursor-pointer"/>
 | 
			
		||||
      <div class="flex gap-[16px] items-center">
 | 
			
		||||
        <span>{{audioProps.currentTime}}</span>
 | 
			
		||||
        <el-slider v-model="audioProps.duration" color="#409eff" class="w-[160px!important] "/>
 | 
			
		||||
        <span>{{ audioProps.duration }}</span>
 | 
			
		||||
      </div>
 | 
			
		||||
      <!-- 音频 -->
 | 
			
		||||
      <audio v-bind="audioProps" ref="audioRef" controls v-show="!audioProps" @timeupdate="audioTimeUpdate">
 | 
			
		||||
        <source :src="response"/>
 | 
			
		||||
      </audio>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <!-- 音量控制器 -->
 | 
			
		||||
    <div class="flex gap-[16px] items-center">
 | 
			
		||||
      <Icon :icon="audioProps.muted ? 'tabler:volume-off' : 'tabler:volume'" :size="20" class="cursor-pointer" @click="toggleStatus('muted')"/>
 | 
			
		||||
      <el-slider v-model="audioProps.volume" color="#409eff" class="w-[160px!important] "/>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { formatPast } from '@/utils/formatTime'
 | 
			
		||||
import response from '@/assets/audio/response.mp3'
 | 
			
		||||
 | 
			
		||||
defineOptions({ name: 'Index' })
 | 
			
		||||
 | 
			
		||||
  const audioRef = ref<Nullable<HTMLElement>>(null)
 | 
			
		||||
    // 音频相关属性https://www.runoob.com/tags/ref-av-dom.html
 | 
			
		||||
  const audioProps = reactive({
 | 
			
		||||
    autoplay: true,
 | 
			
		||||
    paused: false,
 | 
			
		||||
    currentTime: '00:00',
 | 
			
		||||
    duration: '00:00',
 | 
			
		||||
    muted:  false,
 | 
			
		||||
    volume: 50,
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  function toggleStatus (type: string) {
 | 
			
		||||
    audioProps[type] = !audioProps[type]
 | 
			
		||||
    if (type === 'paused' && audioRef.value) {
 | 
			
		||||
      if (audioProps[type]) {
 | 
			
		||||
        audioRef.value.pause()
 | 
			
		||||
      } else {
 | 
			
		||||
        audioRef.value.play()
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // 更新播放位置
 | 
			
		||||
  function audioTimeUpdate (args) {
 | 
			
		||||
    audioProps.currentTime = formatPast(new Date(args.timeStamp), 'mm:ss')
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="flex flex-col h-full">
 | 
			
		||||
  <div class="flex flex-col h-[600px]">
 | 
			
		||||
    <div class="flex-auto flex overflow-hidden">
 | 
			
		||||
      <el-tabs v-model="currentType" class="flex-auto px-[var(--app-content-padding)]">
 | 
			
		||||
        <!-- 我的创作 -->
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <ContentWrap class="w-300px h-full">
 | 
			
		||||
  <ContentWrap class="w-300px h-full mb-[0!important]">
 | 
			
		||||
    <el-radio-group v-model="generateMode" class="mb-15px">
 | 
			
		||||
      <el-radio-button label="desc">
 | 
			
		||||
        描述模式
 | 
			
		||||
@@ -28,10 +28,7 @@ const emits = defineEmits(['generate-music'])
 | 
			
		||||
 | 
			
		||||
const generateMode = ref('lyric')
 | 
			
		||||
 | 
			
		||||
interface ModeRef {
 | 
			
		||||
  formData: Recordable
 | 
			
		||||
}
 | 
			
		||||
const modeRef = ref<ModeRef | null>(null)
 | 
			
		||||
const modeRef = ref<Nullable<{ formData: Recordable }>>(null)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *@Description: 根据信息生成音乐
 | 
			
		||||
 
 | 
			
		||||
@@ -20,17 +20,21 @@ export const AiPlatformEnum = {
 | 
			
		||||
  Ollama: 'Ollama',
 | 
			
		||||
  STABLE_DIFFUSION: 'StableDiffusion', // Stability AI
 | 
			
		||||
  MIDJOURNEY: 'Midjourney', // Midjourney
 | 
			
		||||
  SUNO: 'Suno', // Suno AI
 | 
			
		||||
  SUNO: 'Suno' // Suno AI
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const OtherPlatformEnum:ImageModelVO [] = [
 | 
			
		||||
export const OtherPlatformEnum: ImageModelVO[] = [
 | 
			
		||||
  {
 | 
			
		||||
    key: AiPlatformEnum.TONG_YI,
 | 
			
		||||
    name: '通义万相'
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    key: AiPlatformEnum.YI_YAN,
 | 
			
		||||
    name: '百度图片'
 | 
			
		||||
    name: '百度千帆'
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    key: AiPlatformEnum.ZHI_PU,
 | 
			
		||||
    name: '智谱 AI'
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@@ -60,6 +64,12 @@ export enum AiWriteTypeEnum {
 | 
			
		||||
  REPLY // 回复
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 表格展示对照map
 | 
			
		||||
export const AiWriteTypeTableRender = {
 | 
			
		||||
  [AiWriteTypeEnum.WRITING]: '撰写',
 | 
			
		||||
  [AiWriteTypeEnum.REPLY]: '回复',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ========== 【图片 UI】相关的枚举 ==========
 | 
			
		||||
export const ImageHotWords = [
 | 
			
		||||
  '中国旗袍',
 | 
			
		||||
@@ -200,54 +210,6 @@ export const StableDiffusionStylePresets: ImageModelVO[] = [
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
// todo @芋艿 这些是通义的风格,看要不要删除
 | 
			
		||||
export const TongYiWanXiangStylePresets: ImageModelVO[] = [
 | 
			
		||||
  {
 | 
			
		||||
    key: '-1',
 | 
			
		||||
    name: '上传图像风格'
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    key: '0',
 | 
			
		||||
    name: '复古漫画'
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    key: '1',
 | 
			
		||||
    name: '3D童话'
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    key: '2',
 | 
			
		||||
    name: '二次元'
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    key: '3',
 | 
			
		||||
    name: '小清新'
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    key: '4',
 | 
			
		||||
    name: '未来科技'
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    key: '5',
 | 
			
		||||
    name: '国画古风'
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    key: '6',
 | 
			
		||||
    name: '将军百战'
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    key: '7',
 | 
			
		||||
    name: '炫彩卡通'
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    key: '8',
 | 
			
		||||
    name: '清雅国风'
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    key: '9',
 | 
			
		||||
    name: '喜迎新年'
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
export const TongYiWanXiangModels: ImageModelVO[] = [
 | 
			
		||||
  {
 | 
			
		||||
    key: 'wanx-v1',
 | 
			
		||||
@@ -259,6 +221,20 @@ export const TongYiWanXiangModels: ImageModelVO[] = [
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
export const QianFanModels: ImageModelVO[] = [
 | 
			
		||||
  {
 | 
			
		||||
    key: 'sd_xl',
 | 
			
		||||
    name: 'sd_xl'
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
export const ChatGlmModels: ImageModelVO[] = [
 | 
			
		||||
  {
 | 
			
		||||
    key: 'cogview-3',
 | 
			
		||||
    name: 'cogview-3'
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
export const StableDiffusionClipGuidancePresets: ImageModelVO[] = [
 | 
			
		||||
  {
 | 
			
		||||
    key: 'NONE',
 | 
			
		||||
@@ -318,7 +294,7 @@ export const Dall3StyleList: ImageModelVO[] = [
 | 
			
		||||
 | 
			
		||||
export interface ImageSizeVO {
 | 
			
		||||
  key: string
 | 
			
		||||
  name: string
 | 
			
		||||
  name?: string
 | 
			
		||||
  style: string
 | 
			
		||||
  width: string
 | 
			
		||||
  height: string
 | 
			
		||||
 
 | 
			
		||||
@@ -24,26 +24,28 @@
 | 
			
		||||
    </h3>
 | 
			
		||||
  </DefineLabel>
 | 
			
		||||
 | 
			
		||||
  <div class="relative" v-bind="$attrs">
 | 
			
		||||
  <div class="flex flex-col" v-bind="$attrs">
 | 
			
		||||
    <!-- tab -->
 | 
			
		||||
    <div
 | 
			
		||||
      class="absolute left-1/2 top-2 -translate-x-1/2 w-[303px] rounded-full bg-[#DDDFE3] p-1 z-10"
 | 
			
		||||
    >
 | 
			
		||||
      <div
 | 
			
		||||
        class="flex items-center relative after:content-[''] after:block after:bg-white after:h-[30px] after:w-1/2 after:absolute after:top-0 after:left-0 after:transition-transform after:rounded-full"
 | 
			
		||||
        :class="selectedTab === AiWriteTypeEnum.REPLY && 'after:transform after:translate-x-[100%]'"
 | 
			
		||||
      >
 | 
			
		||||
        <ReuseTab
 | 
			
		||||
          v-for="tab in tabs"
 | 
			
		||||
          :key="tab.value"
 | 
			
		||||
          :text="tab.text"
 | 
			
		||||
          :active="tab.value === selectedTab"
 | 
			
		||||
          :itemClick="() => switchTab(tab.value)"
 | 
			
		||||
        />
 | 
			
		||||
    <div class="w-full pt-2 bg-[#f5f7f9] flex justify-center">
 | 
			
		||||
      <div class="w-[303px] rounded-full bg-[#DDDFE3] p-1 z-10">
 | 
			
		||||
        <div
 | 
			
		||||
          class="flex items-center relative after:content-[''] after:block after:bg-white after:h-[30px] after:w-1/2 after:absolute after:top-0 after:left-0 after:transition-transform after:rounded-full"
 | 
			
		||||
          :class="
 | 
			
		||||
            selectedTab === AiWriteTypeEnum.REPLY && 'after:transform after:translate-x-[100%]'
 | 
			
		||||
          "
 | 
			
		||||
        >
 | 
			
		||||
          <ReuseTab
 | 
			
		||||
            v-for="tab in tabs"
 | 
			
		||||
            :key="tab.value"
 | 
			
		||||
            :text="tab.text"
 | 
			
		||||
            :active="tab.value === selectedTab"
 | 
			
		||||
            :itemClick="() => switchTab(tab.value)"
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div
 | 
			
		||||
      class="px-7 pb-2 pt-[46px] overflow-y-auto lg:block w-[380px] box-border bg-[#ECEDEF] h-full"
 | 
			
		||||
      class="px-7 pb-2 flex-grow overflow-y-auto lg:block w-[380px] box-border bg-[#f5f7f9] h-full"
 | 
			
		||||
    >
 | 
			
		||||
      <div>
 | 
			
		||||
        <template v-if="selectedTab === 1">
 | 
			
		||||
@@ -102,7 +104,7 @@
 | 
			
		||||
import { createReusableTemplate } from '@vueuse/core'
 | 
			
		||||
import { ref } from 'vue'
 | 
			
		||||
import Tag from './Tag.vue'
 | 
			
		||||
import { WriteVO } from '@/api/ai/writer'
 | 
			
		||||
import { WriteVO } from 'src/api/ai/write'
 | 
			
		||||
import { omit } from 'lodash-es'
 | 
			
		||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 | 
			
		||||
import { AiWriteTypeEnum, WriteExample } from '@/views/ai/utils/constants'
 | 
			
		||||
@@ -177,10 +179,18 @@ const initData: WriteVO = {
 | 
			
		||||
}
 | 
			
		||||
const formData = ref<WriteVO>({ ...initData })
 | 
			
		||||
 | 
			
		||||
/** 用来记录切换之前所填写的数据,切换的时候给赋值回来 **/
 | 
			
		||||
const recordFormData = {} as Record<AiWriteTypeEnum, WriteVO>
 | 
			
		||||
 | 
			
		||||
/** 切换tab **/
 | 
			
		||||
const switchTab = (value: TabType) => {
 | 
			
		||||
  selectedTab.value = value
 | 
			
		||||
  formData.value = { ...initData }
 | 
			
		||||
  if (value !== selectedTab.value) {
 | 
			
		||||
    // 保存之前的久数据
 | 
			
		||||
    recordFormData[selectedTab.value] = formData.value
 | 
			
		||||
    selectedTab.value = value
 | 
			
		||||
    // 将之前的旧数据赋值回来
 | 
			
		||||
    formData.value = { ...initData, ...recordFormData[value] }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 提交写作 */
 | 
			
		||||
@@ -1,17 +1,19 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="h-full box-border flex flex-col px-7">
 | 
			
		||||
    <h3 class="m-0 h-14 -mx-7 px-7 shrink-0 flex items-center justify-between bg-[#ecedef]">
 | 
			
		||||
      <span>预览</span>
 | 
			
		||||
      <!-- 展示在右上角 -->
 | 
			
		||||
      <el-button color="#846af7" v-show="showCopy" @click="copyContent" size="small">
 | 
			
		||||
        <template #icon>
 | 
			
		||||
          <Icon icon="ph:copy-bold" />
 | 
			
		||||
        </template>
 | 
			
		||||
        复制
 | 
			
		||||
      </el-button>
 | 
			
		||||
    </h3>
 | 
			
		||||
  <el-card class="my-card h-full">
 | 
			
		||||
    <template #header>
 | 
			
		||||
      <h3 class="m-0 px-7 shrink-0 flex items-center justify-between">
 | 
			
		||||
        <span>预览</span>
 | 
			
		||||
        <!-- 展示在右上角 -->
 | 
			
		||||
        <el-button color="#846af7" v-show="showCopy" @click="copyContent" size="small">
 | 
			
		||||
          <template #icon>
 | 
			
		||||
            <Icon icon="ph:copy-bold" />
 | 
			
		||||
          </template>
 | 
			
		||||
          复制
 | 
			
		||||
        </el-button>
 | 
			
		||||
      </h3>
 | 
			
		||||
    </template>
 | 
			
		||||
 | 
			
		||||
    <div ref="contentRef" class="hide-scroll-bar flex-grow box-border overflow-y-auto">
 | 
			
		||||
    <div ref="contentRef" class="hide-scroll-bar h-full box-border overflow-y-auto">
 | 
			
		||||
      <div class="w-full min-h-full relative flex-grow bg-white box-border p-3 sm:p-7">
 | 
			
		||||
        <!-- 终止生成内容的按钮 -->
 | 
			
		||||
        <el-button
 | 
			
		||||
@@ -36,7 +38,7 @@
 | 
			
		||||
        />
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  </el-card>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
@@ -102,4 +104,17 @@ watch(copied, (val) => {
 | 
			
		||||
    height: 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.my-card {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
 | 
			
		||||
  :deep(.el-card__body) {
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    flex-grow: 1;
 | 
			
		||||
    overflow-y: auto;
 | 
			
		||||
    padding: 0;
 | 
			
		||||
    @extend .hide-scroll-bar;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
<!-- 标签选项 -->
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="flex flex-wrap gap-[8px]">
 | 
			
		||||
    <span
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <!-- TODO @hhhero:整体没啥问题了。感觉整体框框的样子可以优化下,可以参考下绘图界面。例如说:1)写作的“预览”和绘图的“绘图任务”的 header;2)左右的边界,有个竖线之类的。 -->
 | 
			
		||||
  <div class="h-[calc(100vh-var(--top-tool-height)-var(--app-footer-height)-40px)] -m-5 flex">
 | 
			
		||||
  <div class="absolute top-0 left-0 right-0 bottom-0 flex">
 | 
			
		||||
    <Left
 | 
			
		||||
      :is-writing="isWriting"
 | 
			
		||||
      class="h-full"
 | 
			
		||||
@@ -21,7 +20,7 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import Left from './components/Left.vue'
 | 
			
		||||
import Right from './components/Right.vue'
 | 
			
		||||
import * as WriteApi from '@/api/ai/writer'
 | 
			
		||||
import { WriteApi, WriteVO } from '@/api/ai/write'
 | 
			
		||||
import { WriteExample } from '@/views/ai/utils/constants'
 | 
			
		||||
 | 
			
		||||
const message = useMessage()
 | 
			
		||||
@@ -38,7 +37,7 @@ const stopStream = () => {
 | 
			
		||||
 | 
			
		||||
/** 执行写作 */
 | 
			
		||||
const rightRef = ref<InstanceType<typeof Right>>()
 | 
			
		||||
const submit = (data) => {
 | 
			
		||||
const submit = (data: WriteVO) => {
 | 
			
		||||
  abortController.value = new AbortController()
 | 
			
		||||
  writeResult.value = ''
 | 
			
		||||
  isWriting.value = true
 | 
			
		||||
@@ -66,7 +65,7 @@ const submit = (data) => {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 点击示例触发 */
 | 
			
		||||
const handleExampleClick = (type: keyof typeof WriteExampleDataJson) => {
 | 
			
		||||
const handleExampleClick = (type: keyof typeof WriteExample) => {
 | 
			
		||||
  writeResult.value = WriteExample[type].data
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -39,7 +39,7 @@
 | 
			
		||||
        </el-select>
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
      <el-form-item label="平台" prop="platform">
 | 
			
		||||
        <el-select v-model="queryParams.status" placeholder="请选择平台" clearable class="!w-240px">
 | 
			
		||||
        <el-select v-model="queryParams.platform" placeholder="请选择平台" clearable class="!w-240px">
 | 
			
		||||
          <el-option
 | 
			
		||||
            v-for="dict in getStrDictOptions(DICT_TYPE.AI_PLATFORM)"
 | 
			
		||||
            :key="dict.value"
 | 
			
		||||
@@ -70,6 +70,7 @@
 | 
			
		||||
        >
 | 
			
		||||
          <Icon icon="ep:plus" class="mr-5px" /> 新增
 | 
			
		||||
        </el-button>
 | 
			
		||||
        <!-- TODO @YunaiV  目前没有导出接口,需要导出吗 -->
 | 
			
		||||
        <el-button
 | 
			
		||||
          type="success"
 | 
			
		||||
          plain
 | 
			
		||||
@@ -103,7 +104,13 @@
 | 
			
		||||
        </template>
 | 
			
		||||
      </el-table-column>
 | 
			
		||||
      <el-table-column label="模型" align="center" prop="model" width="180" />
 | 
			
		||||
      <el-table-column label="生成内容提示" align="center" prop="prompt" width="180" />
 | 
			
		||||
      <el-table-column
 | 
			
		||||
        label="生成内容提示"
 | 
			
		||||
        align="center"
 | 
			
		||||
        prop="prompt"
 | 
			
		||||
        width="180"
 | 
			
		||||
        show-overflow-tooltip
 | 
			
		||||
      />
 | 
			
		||||
      <el-table-column label="生成的内容" align="center" prop="generatedContent" width="180" />
 | 
			
		||||
      <el-table-column label="原文" align="center" prop="originalContent" width="180" />
 | 
			
		||||
      <el-table-column label="长度" align="center" prop="length">
 | 
			
		||||
@@ -136,6 +143,7 @@
 | 
			
		||||
      <el-table-column label="错误信息" align="center" prop="errorMessage" />
 | 
			
		||||
      <el-table-column label="操作" align="center">
 | 
			
		||||
        <template #default="scope">
 | 
			
		||||
<!--          TODO @YunaiV 目前没有修改接口,写作要可以更改吗-->
 | 
			
		||||
          <el-button
 | 
			
		||||
            link
 | 
			
		||||
            type="primary"
 | 
			
		||||
@@ -168,8 +176,8 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
 | 
			
		||||
import { dateFormatter } from '@/utils/formatTime'
 | 
			
		||||
// TODO 芋艿:这里应该是 write
 | 
			
		||||
import { WriteApi, WriteVO } from '@/api/ai/writer'
 | 
			
		||||
import { useRouter } from 'vue-router'
 | 
			
		||||
import { WriteApi, AiWritePageReqVO, AiWriteRespVo } from '@/api/ai/write'
 | 
			
		||||
import * as UserApi from '@/api/system/user'
 | 
			
		||||
 | 
			
		||||
/** AI 写作列表 */
 | 
			
		||||
@@ -177,17 +185,18 @@ defineOptions({ name: 'AiWriteManager' })
 | 
			
		||||
 | 
			
		||||
const message = useMessage() // 消息弹窗
 | 
			
		||||
const { t } = useI18n() // 国际化
 | 
			
		||||
const router = useRouter() // 路由
 | 
			
		||||
 | 
			
		||||
const loading = ref(true) // 列表的加载中
 | 
			
		||||
const list = ref<WriteVO[]>([]) // 列表的数据
 | 
			
		||||
const list = ref<AiWriteRespVo[]>([]) // 列表的数据
 | 
			
		||||
const total = ref(0) // 列表的总页数
 | 
			
		||||
const queryParams = reactive({
 | 
			
		||||
const queryParams = reactive<AiWritePageReqVO>({
 | 
			
		||||
  pageNo: 1,
 | 
			
		||||
  pageSize: 10,
 | 
			
		||||
  userId: undefined,
 | 
			
		||||
  type: undefined,
 | 
			
		||||
  platform: undefined,
 | 
			
		||||
  createTime: []
 | 
			
		||||
  createTime: undefined
 | 
			
		||||
})
 | 
			
		||||
const queryFormRef = ref() // 搜索的表单
 | 
			
		||||
const userList = ref<UserApi.UserVO[]>([]) // 用户列表
 | 
			
		||||
@@ -216,6 +225,15 @@ const resetQuery = () => {
 | 
			
		||||
  handleQuery()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 新增方法,跳转到写作页面 **/
 | 
			
		||||
const openForm = (type: string, id?: number) => {
 | 
			
		||||
  switch (type) {
 | 
			
		||||
    case 'create':
 | 
			
		||||
      router.push('/ai/write')
 | 
			
		||||
      break
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 删除按钮操作 */
 | 
			
		||||
const handleDelete = async (id: number) => {
 | 
			
		||||
  try {
 | 
			
		||||
 
 | 
			
		||||
@@ -28,9 +28,7 @@ const message = useMessage() // 消息弹窗
 | 
			
		||||
 | 
			
		||||
// ======================= WebSocket start =======================
 | 
			
		||||
const server = ref(
 | 
			
		||||
  (import.meta.env.VITE_BASE_URL + '/infra/ws/').replace('http', 'ws') +
 | 
			
		||||
    '?token=' +
 | 
			
		||||
    getAccessToken()
 | 
			
		||||
  (import.meta.env.VITE_BASE_URL + '/infra/ws').replace('http', 'ws') + '?token=' + getAccessToken()
 | 
			
		||||
) // WebSocket 服务地址
 | 
			
		||||
 | 
			
		||||
/** 发起 WebSocket 连接 */
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								types/global.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								types/global.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -50,4 +50,9 @@ declare global {
 | 
			
		||||
    name: string
 | 
			
		||||
    children?: Tree[] | any[]
 | 
			
		||||
  }
 | 
			
		||||
  // 分页数据公共返回
 | 
			
		||||
  interface PageResult<T> {
 | 
			
		||||
    list: T // 数据
 | 
			
		||||
    total: number // 总量
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user