Compare commits
No commits in common. "a31352b8f51c94da6f541d2508cb0e77c45b6673" and "bcd6f63bb308cf5bb0c99046cd1db3751faaf14d" have entirely different histories.
a31352b8f5
...
bcd6f63bb3
|
|
@ -49,9 +49,6 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="WebUI\dist\**\*.*">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<Content Update="appsettings.json">
|
<Content Update="appsettings.json">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"dotnetRunMessages": true,
|
"dotnetRunMessages": true,
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"launchUrl": "ui/index.html",
|
"launchUrl": "/swagger/index.html",
|
||||||
"applicationUrl": "http://*:5238",
|
"applicationUrl": "http://*:5238",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# 线上环境平台打包路径
|
# 线上环境平台打包路径
|
||||||
VITE_PUBLIC_PATH = /ui/
|
VITE_PUBLIC_PATH = /
|
||||||
|
|
||||||
# 线上环境路由历史模式(Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数")
|
# 线上环境路由历史模式(Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数")
|
||||||
VITE_ROUTER_HISTORY = "hash"
|
VITE_ROUTER_HISTORY = "hash"
|
||||||
|
|
@ -13,4 +13,7 @@ VITE_CDN = false
|
||||||
VITE_COMPRESSION = "none"
|
VITE_COMPRESSION = "none"
|
||||||
|
|
||||||
|
|
||||||
VITE_API_BASEURL = "/"
|
# 接口地址
|
||||||
|
VITE_API_BASEURL = "https://learn-archives-admin.23544.com/api"
|
||||||
|
#数据中心后台地址
|
||||||
|
VITE_API_USERCENTER_URL = "https://dcb.23544.com/api"
|
||||||
|
|
@ -56,12 +56,3 @@ export const ShowTaskInfo = (id: any) => {
|
||||||
params: { id }
|
params: { id }
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** 展示数据 */
|
|
||||||
export const RunningTaskList = (data: any) => {
|
|
||||||
return http.request<any>("post", "/api/VideoTask/RunningTaskList", {
|
|
||||||
data
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { promises } from "node:dns";
|
|
||||||
import { Ref } from "vue";
|
import { Ref } from "vue";
|
||||||
import { array } from "vue-types";
|
import { array } from "vue-types";
|
||||||
|
|
||||||
|
|
@ -327,11 +326,8 @@ export class SearchConditions {
|
||||||
|
|
||||||
/** 表格配置 */
|
/** 表格配置 */
|
||||||
export interface TableConfig {
|
export interface TableConfig {
|
||||||
/** 搜索回调函数 [返回值为true则不调用基础PageAPI]*/
|
/** 搜索回调函数 */
|
||||||
searchCallback?: (
|
searchCallback?: (s: SearchConditions) => void;
|
||||||
s: SearchConditions,
|
|
||||||
tv: TableConfig
|
|
||||||
) => Promise<boolean> | Promise<void> | boolean | void;
|
|
||||||
/** 新增/修改回调函数 */
|
/** 新增/修改回调函数 */
|
||||||
editCallback?: (from: any) => void;
|
editCallback?: (from: any) => void;
|
||||||
/** 编辑表单初始化回调函数 */
|
/** 编辑表单初始化回调函数 */
|
||||||
|
|
|
||||||
|
|
@ -103,11 +103,10 @@ const appB_S = ref<HTMLElement>(null);
|
||||||
function appStyle() {
|
function appStyle() {
|
||||||
if (tableHeight.value !== 0) return;
|
if (tableHeight.value !== 0) return;
|
||||||
tableHeight.value =
|
tableHeight.value =
|
||||||
appB.value.parentElement.parentElement.parentElement.offsetHeight -
|
appB.value.parentElement.parentElement.offsetHeight -
|
||||||
145 -
|
145 -
|
||||||
appB_S.value.offsetHeight +
|
appB_S.value.offsetHeight +
|
||||||
0;
|
0;
|
||||||
console.log("tableHeight.value", tableHeight.value);
|
|
||||||
return tableHeight;
|
return tableHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -289,7 +288,7 @@ function searchReload() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 查询
|
// 查询
|
||||||
async function handleReloadPaged(reload = true) {
|
function handleReloadPaged(reload = true) {
|
||||||
if (defaultOrderBy == null) {
|
if (defaultOrderBy == null) {
|
||||||
defaultOrderBy = {
|
defaultOrderBy = {
|
||||||
OrderBy: table.value.search.OrderBy,
|
OrderBy: table.value.search.OrderBy,
|
||||||
|
|
@ -333,9 +332,12 @@ async function handleReloadPaged(reload = true) {
|
||||||
if (!reload && table.value.search.Conditions.length > 0) {
|
if (!reload && table.value.search.Conditions.length > 0) {
|
||||||
table.value.search.PageIndex = 0;
|
table.value.search.PageIndex = 0;
|
||||||
}
|
}
|
||||||
|
if (table.value.searchCallback) {
|
||||||
|
table.value.searchCallback(table.value.search);
|
||||||
|
}
|
||||||
//如果有展开行 则全部收回
|
//如果有展开行 则全部收回
|
||||||
if (table.value.expandColumn) expands.value = [];
|
if (table.value.expandColumn) expands.value = [];
|
||||||
return fetchPagedData();
|
fetchPagedData();
|
||||||
}
|
}
|
||||||
// 加载前置数据(如查询条件的下拉选择数据)
|
// 加载前置数据(如查询条件的下拉选择数据)
|
||||||
async function fetchInitData() {
|
async function fetchInitData() {
|
||||||
|
|
@ -358,10 +360,7 @@ function getByteLen(str) {
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
// 加载分页数据
|
// 加载分页数据
|
||||||
async function fetchPagedData() {
|
function fetchPagedData() {
|
||||||
if (table.value.searchCallback) {
|
|
||||||
if (await table.value.searchCallback(table.value.search, table.value)) return;
|
|
||||||
}
|
|
||||||
for (const iterator of table.value.search.defaultConditions) {
|
for (const iterator of table.value.search.defaultConditions) {
|
||||||
if (!iterator) continue;
|
if (!iterator) continue;
|
||||||
if (!table.value.search.Conditions.find((s) => s == iterator)) {
|
if (!table.value.search.Conditions.find((s) => s == iterator)) {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import {
|
||||||
ComboModel,
|
ComboModel,
|
||||||
ConditionalType,
|
ConditionalType,
|
||||||
intTableData,
|
intTableData,
|
||||||
SearchConditions,
|
|
||||||
TableColumnSearch,
|
TableColumnSearch,
|
||||||
TableConfig,
|
TableConfig,
|
||||||
} from "@/components/hTable/hTable";
|
} from "@/components/hTable/hTable";
|
||||||
|
|
@ -18,7 +17,6 @@ import { ReStart, RowRload } from "@/api/videoTask";
|
||||||
import { Refresh } from "@element-plus/icons-vue";
|
import { Refresh } from "@element-plus/icons-vue";
|
||||||
import { message } from "@/utils/message";
|
import { message } from "@/utils/message";
|
||||||
import { json } from "stream/consumers";
|
import { json } from "stream/consumers";
|
||||||
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
|
|
||||||
|
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
|
|
@ -28,20 +26,15 @@ defineOptions({
|
||||||
name: ControllerName,
|
name: ControllerName,
|
||||||
});
|
});
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
searchCallback?: (
|
|
||||||
s: SearchConditions,
|
|
||||||
tv: TableConfig
|
|
||||||
) => boolean | Promise<boolean> | void;
|
|
||||||
}>();
|
|
||||||
const route = useRouter();
|
const route = useRouter();
|
||||||
|
function searchCallback(data) {}
|
||||||
const table = ref<{ initTable: (config: TableConfig) => void }>();
|
const table = ref<{ initTable: (config: TableConfig) => void }>();
|
||||||
const tableData: TableConfig = intTableData({
|
const tableData: TableConfig = intTableData({
|
||||||
apiUrl: ControllerName,
|
apiUrl: ControllerName,
|
||||||
expandColumn: true,
|
expandColumn: true,
|
||||||
selectColumn: false, // 列表选择
|
selectColumn: false, // 列表选择
|
||||||
border: false, // 是否显示表格边框
|
border: false, // 是否显示表格边框
|
||||||
searchCallback: props.searchCallback,
|
searchCallback: searchCallback,
|
||||||
expandChange: expandChange,
|
expandChange: expandChange,
|
||||||
search: {
|
search: {
|
||||||
// 查询条件
|
// 查询条件
|
||||||
|
|
@ -129,25 +122,6 @@ async function submitRowRload() {
|
||||||
async function expandChange(row: any, expandedRows: any[]) {
|
async function expandChange(row: any, expandedRows: any[]) {
|
||||||
if (expandedRows.find((s) => s == row)) RloadTaskInfo(row);
|
if (expandedRows.find((s) => s == row)) RloadTaskInfo(row);
|
||||||
}
|
}
|
||||||
function previewTask(row: any) {
|
|
||||||
let pageName = "showTask";
|
|
||||||
let queryData = { id: row.id.toString() };
|
|
||||||
useMultiTagsStoreHook().handleTags("push", {
|
|
||||||
path: `/welcome/showTask_` + row.id,
|
|
||||||
name: pageName,
|
|
||||||
query: queryData,
|
|
||||||
meta: {
|
|
||||||
title: `任务预览` + row.id.toString().slice(-4),
|
|
||||||
dynamicLevel: 3,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
// 路由跳转
|
|
||||||
route.push({ name: pageName, query: queryData });
|
|
||||||
}
|
|
||||||
function firstLetterToLower(str) {
|
|
||||||
if (typeof str !== "string" || !str) return str;
|
|
||||||
return str[0].toLowerCase() + str.slice(1);
|
|
||||||
}
|
|
||||||
async function RloadTaskInfo(row: any) {
|
async function RloadTaskInfo(row: any) {
|
||||||
let res = await RowRload(row.id);
|
let res = await RowRload(row.id);
|
||||||
row.TaskInfo = res;
|
row.TaskInfo = res;
|
||||||
|
|
@ -158,7 +132,7 @@ async function RloadTaskInfo(row: any) {
|
||||||
if (row.TaskInfo.startTime != null) {
|
if (row.TaskInfo.startTime != null) {
|
||||||
for (const element of row.TaskInfo.stepData) {
|
for (const element of row.TaskInfo.stepData) {
|
||||||
element.time = formatDateToChinese(
|
element.time = formatDateToChinese(
|
||||||
row.TaskInfo.startTime[firstLetterToLower(element.title)]
|
row.TaskInfo.startTime[element.title.toLowerCase()]
|
||||||
);
|
);
|
||||||
let i = row.TaskInfo.stepData.indexOf(element);
|
let i = row.TaskInfo.stepData.indexOf(element);
|
||||||
if (i < row.TaskInfo.active) {
|
if (i < row.TaskInfo.active) {
|
||||||
|
|
@ -210,12 +184,10 @@ const stepData = ref<StepData[]>([
|
||||||
<!-- 拓展内容 -->
|
<!-- 拓展内容 -->
|
||||||
<div class="expanded-content expandSlot">
|
<div class="expanded-content expandSlot">
|
||||||
<h3>任务详情</h3>
|
<h3>任务详情</h3>
|
||||||
<div class="InfoEx" v-if="props.row.TaskInfo != null">
|
<div class="InfoEx">
|
||||||
<div>
|
<div>
|
||||||
<span>进度</span>
|
<span>进度</span>
|
||||||
<div class="content">
|
<div class="content">{{ props.row.lastEnum }} {{ props.row.progress }}</div>
|
||||||
{{ props.row.TaskInfo.lastEnum }} {{ props.row.TaskInfo.progress }}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>操作</span>
|
<span>操作</span>
|
||||||
|
|
@ -226,8 +198,19 @@ const stepData = ref<StepData[]>([
|
||||||
@click="RloadTaskInfo(props.row)"
|
@click="RloadTaskInfo(props.row)"
|
||||||
circle
|
circle
|
||||||
/>
|
/>
|
||||||
<el-button type="danger" @click="showDialog(props.row)">重试</el-button>
|
<el-button type="danger" @click="showDialog(props.row.id)"
|
||||||
<el-button type="primary" @click="previewTask(props.row)">预览</el-button>
|
>重试</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
@click="
|
||||||
|
route.push({
|
||||||
|
path: '/welcome/showTask',
|
||||||
|
query: { id: props.row.id.toString() },
|
||||||
|
})
|
||||||
|
"
|
||||||
|
>预览</el-button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,233 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import ahTable from "@/components/hTable/index.vue";
|
|
||||||
import {
|
|
||||||
ComboModel,
|
|
||||||
ConditionalType,
|
|
||||||
intTableData,
|
|
||||||
SearchConditions,
|
|
||||||
TableColumnSearch,
|
|
||||||
TableConfig,
|
|
||||||
} from "@/components/hTable/hTable";
|
|
||||||
import { onMounted, ref } from "vue";
|
|
||||||
import { getenum } from "@/api/enum";
|
|
||||||
import { ElMessage } from "element-plus";
|
|
||||||
import { ReStart, RowRload, RunningTaskList } from "@/api/videoTask";
|
|
||||||
import { Refresh } from "@element-plus/icons-vue";
|
|
||||||
import { message } from "@/utils/message";
|
|
||||||
import videoTask from "./index.vue";
|
|
||||||
|
|
||||||
defineOptions({
|
|
||||||
name: `runningTask`,
|
|
||||||
});
|
|
||||||
async function searchCallback(s: SearchConditions, tv: TableConfig): Promise<boolean> {
|
|
||||||
//自定义搜索回调函数
|
|
||||||
let res = await RunningTaskList(s);
|
|
||||||
tv.data = res.data.map((s, i) => {
|
|
||||||
return { ...s, customId: i };
|
|
||||||
});
|
|
||||||
tv.pageData = res;
|
|
||||||
return true;
|
|
||||||
//返回true则不调用基础搜索API
|
|
||||||
}
|
|
||||||
onMounted(async () => {
|
|
||||||
//初始化数据
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div id="video-container">
|
||||||
<videoTask :searchCallback="searchCallback"></videoTask>
|
<div v-if="videoKnows.length > 0">
|
||||||
|
<div id="segmentsContainer" class="sc" :class="{ locked: isLocked }">
|
||||||
|
<h2>
|
||||||
|
<button class="gudingBtn" @click="toggleLock">
|
||||||
|
{{ isLocked ? "🔓" : "🔒" }}
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div v-for="(item, index) in videoKnows" :key="index" class="knowDiv">
|
||||||
|
<div class="knowTtile">
|
||||||
|
<div style="cursor: pointer" @click="spClick(index, $event)">
|
||||||
|
<div class="knowTtileTheme">{{ getTimeRange(item) }} {{ item.Theme }}</div>
|
||||||
|
<span class="kSpan">#{{ item.KnowPointId }} {{ item.KnowPoint }}</span>
|
||||||
|
</div>
|
||||||
|
<div>概览: {{ item.Content }}</div>
|
||||||
|
<br />
|
||||||
|
<div v-if="item.QuestionArr && item.QuestionArr.length > 0">
|
||||||
|
<div
|
||||||
|
v-for="(q, qIndex) in item.QuestionArr"
|
||||||
|
:key="qIndex"
|
||||||
|
class="knowQuestion"
|
||||||
|
@click="spClickTime(q.startTime)"
|
||||||
|
>
|
||||||
|
<h3>
|
||||||
|
问题: <span class="kSpan">{{ q.startTime }} 秒</span>
|
||||||
|
</h3>
|
||||||
|
<div class="kSpan">{{ q.topicStem }}</div>
|
||||||
|
<div>{{ q.question }}</div>
|
||||||
|
<img
|
||||||
|
style="text-align: center"
|
||||||
|
:src="q.pPTImageUrl"
|
||||||
|
width="320"
|
||||||
|
height="180"
|
||||||
|
:alt="'问题图片' + qIndex"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
<button class="kBtn" @click="spClick(index, $event)">
|
||||||
|
<span>{{ getFirstChar(item.Theme) }} {{ item.Theme }}</span>
|
||||||
|
<br />
|
||||||
|
<span class="kSpan textEllipsis"
|
||||||
|
>#{{ item.KnowPointId }} {{ item.KnowPoint }}</span
|
||||||
|
>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<video ref="videoPlayerEL" controls autoplay>
|
||||||
|
<source :src="videoSrc" type="video/mp4" />
|
||||||
|
</video>
|
||||||
|
<div ref="subtitleAreaEL" class="subtitles">{{ currentSubtitle }}</div>
|
||||||
|
<div ref="subtitleArea1EL" class="subtitles" :style="subtitleStyle">
|
||||||
|
{{ currentSubtitle1 }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { SenseVoiceRes, ShowTaskInfo, VideoKnowRes } from "@/api/videoTask";
|
||||||
|
import { message } from "@/utils/message";
|
||||||
|
import { isEmpty } from "@pureadmin/utils";
|
||||||
|
import { ref, onMounted, nextTick } from "vue";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: "runningTask",
|
||||||
|
});
|
||||||
|
|
||||||
|
const subtitleAreaEL = ref<HTMLElement | null>(null);
|
||||||
|
const subtitleArea1EL = ref<HTMLElement | null>(null);
|
||||||
|
const videoPlayerEL = ref<HTMLVideoElement | null>(null);
|
||||||
|
|
||||||
|
// 响应式数据
|
||||||
|
const videoKnows = ref<VideoKnowRes[]>([]);
|
||||||
|
const currentSubtitle = ref("");
|
||||||
|
const currentSubtitle1 = ref("");
|
||||||
|
const isLocked = ref(false);
|
||||||
|
const displayButton = ref<any[]>([]);
|
||||||
|
const lastSegments = ref<any>(null);
|
||||||
|
const videoSrc = ref("");
|
||||||
|
const subtitles = ref<SenseVoiceRes[]>([]);
|
||||||
|
const b1 = ref([]);
|
||||||
|
const subtitles1 = ref<SenseVoiceRes[]>([]);
|
||||||
|
|
||||||
|
// 计算样式
|
||||||
|
const subtitleStyle = {
|
||||||
|
bottom: "101px",
|
||||||
|
backgroundColor: "rgb(99 129 103 / 50%)",
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取首字符
|
||||||
|
const getFirstChar = (str: string): string => {
|
||||||
|
return str ? str.charAt(0) : "";
|
||||||
|
};
|
||||||
|
|
||||||
|
// 切换锁定状态
|
||||||
|
const toggleLock = () => {
|
||||||
|
isLocked.value = !isLocked.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 点击知识点
|
||||||
|
const spClick = (index: number, event: Event) => {
|
||||||
|
if (videoPlayerEL && displayButton.value[index]) {
|
||||||
|
videoPlayerEL.value.currentTime = displayButton.value[index].startTime;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 点击时间跳转
|
||||||
|
const spClickTime = (startTime: number) => {
|
||||||
|
if (videoPlayerEL) {
|
||||||
|
videoPlayerEL.value.currentTime = startTime;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化知识点按钮
|
||||||
|
const initKD = () => {
|
||||||
|
const btns = document.getElementsByClassName("kBtn");
|
||||||
|
if (btns.length === 0) return;
|
||||||
|
|
||||||
|
displayButton.value = b1.value.map((s: any, i: number) => {
|
||||||
|
return { ...s, button: btns[i] };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 设置数据(模拟从后端获取)
|
||||||
|
const setDB = (
|
||||||
|
a: SenseVoiceRes[],
|
||||||
|
a1: SenseVoiceRes[],
|
||||||
|
videoKnows: VideoKnowRes[],
|
||||||
|
c: string
|
||||||
|
) => {
|
||||||
|
subtitles.value = a;
|
||||||
|
subtitles1.value = a1;
|
||||||
|
b1.value = videoKnows;
|
||||||
|
videoSrc.value = c;
|
||||||
|
|
||||||
|
// 初始化视频数据
|
||||||
|
init();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
const init = () => {
|
||||||
|
if (!videoPlayerEL) return;
|
||||||
|
|
||||||
|
// 视频时间变化监听
|
||||||
|
videoPlayerEL.value.addEventListener("timeupdate", function () {
|
||||||
|
if (displayButton.value.length === 0) initKD();
|
||||||
|
|
||||||
|
const currentTime = videoPlayerEL.value.currentTime;
|
||||||
|
if (subtitleAreaEL) subtitleAreaEL.value.textContent = "";
|
||||||
|
if (subtitleArea1EL) subtitleArea1EL.value.textContent = "";
|
||||||
|
|
||||||
|
// 更新字幕
|
||||||
|
subtitles.value.forEach((subtitle, index) => {
|
||||||
|
if (
|
||||||
|
currentTime >= subtitle.start &&
|
||||||
|
currentTime <= subtitle.end &&
|
||||||
|
subtitleAreaEL &&
|
||||||
|
subtitleAreaEL.value.textContent !== subtitle.text
|
||||||
|
) {
|
||||||
|
currentSubtitle.value = subtitle.text;
|
||||||
|
currentSubtitle1.value = subtitles1.value[index]?.text || "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 更新当前时间段
|
||||||
|
const segment = displayButton.value.findLast((s: any) => currentTime >= s.startTime);
|
||||||
|
if (segment) {
|
||||||
|
segment.button.style.backgroundColor = "rgb(238, 200, 118)";
|
||||||
|
if (lastSegments.value && lastSegments.value !== segment) {
|
||||||
|
lastSegments.value.button.style.backgroundColor = "rgb(240, 249, 235)";
|
||||||
|
}
|
||||||
|
lastSegments.value = segment;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 扩展功能:格式化开始和结束时间范围
|
||||||
|
* @param segment 包含 StartTime 和 EndTime 的对象
|
||||||
|
* @returns 格式化的时间范围字符串 (MM:SS - MM:SS)
|
||||||
|
*/
|
||||||
|
function getTimeRange(segment: VideoKnowRes): string {
|
||||||
|
const startTime = segment.startTime ?? 0;
|
||||||
|
|
||||||
|
const startMinutes = Math.floor(startTime / 60);
|
||||||
|
const startSeconds = Math.floor(startTime % 60);
|
||||||
|
|
||||||
|
const sf = startMinutes.toString().padStart(2, "0");
|
||||||
|
const sm = startSeconds.toString().padStart(2, "0");
|
||||||
|
|
||||||
|
return `${sf}:${sm}`;
|
||||||
|
}
|
||||||
|
// 组件挂载后
|
||||||
|
onMounted(async () => {
|
||||||
|
// 初始化MathJax
|
||||||
|
if (window.MathJax) {
|
||||||
|
window.MathJax = {
|
||||||
|
tex: {
|
||||||
|
inlineMath: [
|
||||||
|
["$", "$"],
|
||||||
|
["\\(", "\\)"],
|
||||||
|
],
|
||||||
|
displayMath: [
|
||||||
|
["$$", "$$"],
|
||||||
|
["\\[", "\\]"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 获取当前路由对象
|
||||||
|
const route = useRoute();
|
||||||
|
const data = isEmpty(route.params) ? route.query : route.params;
|
||||||
|
if (isEmpty(data.id) || data.id == null) {
|
||||||
|
message("无效的任务", { type: "warning" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let info = await ShowTaskInfo(data.id);
|
||||||
|
debugger;
|
||||||
|
setDB(info.captions, info.captions1, info.VideoKnows, info.MediaUrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 扩展Window接口以包含全局变量
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
MathJax: any;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,11 @@
|
||||||
<div id="video-container">
|
<div id="video-container">
|
||||||
<div v-if="videoKnows.length > 0">
|
<div v-if="videoKnows.length > 0">
|
||||||
<div id="segmentsContainer" class="sc" :class="{ locked: isLocked }">
|
<div id="segmentsContainer" class="sc" :class="{ locked: isLocked }">
|
||||||
<div>
|
<h2>
|
||||||
<h2>
|
<button class="gudingBtn" @click="toggleLock">
|
||||||
<button class="gudingBtn" @click="toggleLock">
|
{{ isLocked ? "🔓" : "🔒" }}
|
||||||
{{ isLocked ? "🔓" : "🔒" }}</button
|
</button>
|
||||||
>视频分段
|
</h2>
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
<div v-for="(item, index) in videoKnows" :key="index" class="knowDiv">
|
<div v-for="(item, index) in videoKnows" :key="index" class="knowDiv">
|
||||||
<div class="knowTtile">
|
<div class="knowTtile">
|
||||||
<div style="cursor: pointer" @click="spClick(index, $event)">
|
<div style="cursor: pointer" @click="spClick(index, $event)">
|
||||||
|
|
@ -139,13 +137,7 @@ const setDB = (
|
||||||
videoKnows.value = vKnows;
|
videoKnows.value = vKnows;
|
||||||
videoSrc.value = c;
|
videoSrc.value = c;
|
||||||
videoPlayerEL.value?.load();
|
videoPlayerEL.value?.load();
|
||||||
try {
|
videoPlayerEL.value?.play();
|
||||||
nextTick(() => {
|
|
||||||
initKD();
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error("视频自动播放失败:", error);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
function timeupdateVideo() {
|
function timeupdateVideo() {
|
||||||
if (displayButton.value.length === 0) initKD();
|
if (displayButton.value.length === 0) initKD();
|
||||||
|
|
@ -262,6 +254,7 @@ video {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
/* border-radius: 16px; */
|
/* border-radius: 16px; */
|
||||||
line-height: 27px;
|
line-height: 27px;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtitles {
|
.subtitles {
|
||||||
|
|
@ -296,7 +289,7 @@ video {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
align-content: flex-start;
|
align-content: flex-start;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: flex-start;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.kBtn {
|
.kBtn {
|
||||||
|
|
@ -319,7 +312,6 @@ video {
|
||||||
.kBtn:hover {
|
.kBtn:hover {
|
||||||
background-color: rgb(248, 230, 191) !important;
|
background-color: rgb(248, 230, 191) !important;
|
||||||
border: 1px solid rgb(206, 187, 81);
|
border: 1px solid rgb(206, 187, 81);
|
||||||
display: block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.knowDiv {
|
.knowDiv {
|
||||||
|
|
@ -331,9 +323,7 @@ video {
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background-color: #cddc393d;
|
background-color: #cddc393d;
|
||||||
}
|
}
|
||||||
.knowDiv:hover .kBtn {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.knowDiv:hover .knowTtile {
|
.knowDiv:hover .knowTtile {
|
||||||
width: 340px;
|
width: 340px;
|
||||||
display: block;
|
display: block;
|
||||||
|
|
@ -342,7 +332,7 @@ video {
|
||||||
}
|
}
|
||||||
|
|
||||||
.knowTtile {
|
.knowTtile {
|
||||||
/* position: absolute; */
|
position: absolute;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,7 @@ namespace VideoAnalysisCore.Controllers
|
||||||
await baseService.UpdateAsync(task);
|
await baseService.UpdateAsync(task);
|
||||||
}
|
}
|
||||||
//todo重新开始执行GPT分析
|
//todo重新开始执行GPT分析
|
||||||
return BadRequest("任务未实现");
|
return BadRequest("任务为实现");
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -270,7 +270,7 @@ namespace VideoAnalysisCore.Controllers
|
||||||
public async Task ReStart(long id, RedisChannelEnum selectEnum)
|
public async Task ReStart(long id, RedisChannelEnum selectEnum)
|
||||||
{
|
{
|
||||||
await redisManager.ClearTaskError(id);
|
await redisManager.ClearTaskError(id);
|
||||||
_ = Task.Run(async () =>
|
await Task.Run(async () =>
|
||||||
await redisManager.InsertChannel(selectEnum, id)
|
await redisManager.InsertChannel(selectEnum, id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -356,32 +356,8 @@ namespace VideoAnalysisCore.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 预览任务结果
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="model">查询模型</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<object> RunningTaskList([FromBody] QueryRequestBase model)
|
|
||||||
{
|
|
||||||
var oldTaskArr = redisManager.Redis.LRange<long>(RedisExpandKey.IDTask, 0, 999);
|
|
||||||
var sqlquery = base.BaseQuery(model)
|
|
||||||
.Where(s => oldTaskArr.Contains(s.Id))
|
|
||||||
.Select(s => new VideoTask
|
|
||||||
{
|
|
||||||
Id = s.Id,
|
|
||||||
TagId = s.TagId,
|
|
||||||
VideoType = s.VideoType,
|
|
||||||
LastEnum = s.LastEnum,
|
|
||||||
Subject = s.Subject,
|
|
||||||
ComeFrom = s.ComeFrom,
|
|
||||||
MediaUrl = s.MediaUrl,
|
|
||||||
CreateTime = s.CreateTime,
|
|
||||||
});
|
|
||||||
RefAsync<int> total = 0;
|
|
||||||
var data = await sqlquery.ToPageListAsync(model.PageIndex + 1, model.PageSize, total);
|
|
||||||
return new PageResult<VideoTask>() { Data = data, Total = total };
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue