chore: format code style and update linting configuration

This commit is contained in:
Megghy
2025-10-02 10:38:23 +08:00
parent 6fd046adcd
commit 758549d29d
253 changed files with 16258 additions and 15833 deletions

View File

@@ -1,68 +1,69 @@
<script setup lang="ts">
import { NSpace, NSwitch, NInputNumber, NInput, NCollapseItem, NCollapse } from 'naive-ui';
import { AutoActionItem, TriggerType } from '@/client/store/useAutoAction';
import { computed } from 'vue';
import { createDefaultAutoAction } from '@/client/store/autoAction/utils';
import type { AutoActionItem } from '@/client/store/useAutoAction'
import { NCollapse, NCollapseItem, NInput, NInputNumber, NSpace, NSwitch } from 'naive-ui'
import { computed } from 'vue'
import { createDefaultAutoAction } from '@/client/store/autoAction/utils'
import { TriggerType } from '@/client/store/useAutoAction'
const props = defineProps({
action: {
type: Object as () => AutoActionItem,
required: true
}
});
required: true,
},
})
// 根据触发类型判断是否显示用户过滤选项
const showUserFilter = computed(() => {
return ![TriggerType.SCHEDULED].includes(props.action.triggerType);
});
return ![TriggerType.SCHEDULED].includes(props.action.triggerType)
})
// 获取默认配置作为比较基准
const defaultAction = computed(() => createDefaultAutoAction(props.action.triggerType));
const defaultAction = computed(() => createDefaultAutoAction(props.action.triggerType))
// 检查设置项是否被修改
const isModified = (path: string, value: any) => {
const pathParts = path.split('.');
let defaultValue: any = defaultAction.value;
let currentValue: any = props.action;
function isModified(path: string, value: any) {
const pathParts = path.split('.')
let defaultValue: any = defaultAction.value
let currentValue: any = props.action
// 遍历路径获取值
for (const part of pathParts) {
defaultValue = defaultValue && typeof defaultValue === 'object' ? defaultValue[part as keyof typeof defaultValue] : undefined;
currentValue = currentValue && typeof currentValue === 'object' ? currentValue[part as keyof typeof currentValue] : undefined;
defaultValue = defaultValue && typeof defaultValue === 'object' ? defaultValue[part as keyof typeof defaultValue] : undefined
currentValue = currentValue && typeof currentValue === 'object' ? currentValue[part as keyof typeof currentValue] : undefined
}
// 处理特殊情况,如果指定了具体值进行比较
if (value !== undefined) {
return value !== defaultValue;
return value !== defaultValue
}
return currentValue !== defaultValue;
};
return currentValue !== defaultValue
}
// 检查用户过滤区域是否有修改
const userFilterModified = computed(() => {
if (!showUserFilter.value) return false;
return isModified('triggerConfig.userFilterEnabled', props.action.triggerConfig.userFilterEnabled) ||
isModified('triggerConfig.requireMedal', props.action.triggerConfig.requireMedal) ||
isModified('triggerConfig.requireCaptain', props.action.triggerConfig.requireCaptain);
});
if (!showUserFilter.value) return false
return isModified('triggerConfig.userFilterEnabled', props.action.triggerConfig.userFilterEnabled)
|| isModified('triggerConfig.requireMedal', props.action.triggerConfig.requireMedal)
|| isModified('triggerConfig.requireCaptain', props.action.triggerConfig.requireCaptain)
})
// 检查冷却控制区域是否有修改
const cooldownModified = computed(() => {
return isModified('ignoreCooldown', props.action.ignoreCooldown) ||
isModified('actionConfig.delaySeconds', props.action.actionConfig.delaySeconds) ||
isModified('actionConfig.cooldownSeconds', props.action.actionConfig.cooldownSeconds);
});
return isModified('ignoreCooldown', props.action.ignoreCooldown)
|| isModified('actionConfig.delaySeconds', props.action.actionConfig.delaySeconds)
|| isModified('actionConfig.cooldownSeconds', props.action.actionConfig.cooldownSeconds)
})
// 检查逻辑表达式是否有修改
const logicalExpressionModified = computed(() => {
return isModified('logicalExpression', props.action.logicalExpression);
});
return isModified('logicalExpression', props.action.logicalExpression)
})
// 检查自定义JS是否有修改
const customJsModified = computed(() => {
return isModified('executeCommand', props.action.executeCommand);
});
return isModified('executeCommand', props.action.executeCommand)
})
</script>
<template>
@@ -73,7 +74,7 @@ const customJsModified = computed(() => {
:title="userFilterModified ? '用户过滤 *' : '用户过滤'"
:title-extra="userFilterModified ? '已修改' : ''"
class="settings-section"
:class="{'section-modified': userFilterModified}"
:class="{ 'section-modified': userFilterModified }"
>
<div>
<NSpace
@@ -85,7 +86,7 @@ const customJsModified = computed(() => {
align="center"
justify="space-between"
style="width: 100%"
:class="['setting-item', {'setting-modified': isModified('triggerConfig.userFilterEnabled', action.triggerConfig.userFilterEnabled)}]"
class="setting-item" :class="[{ 'setting-modified': isModified('triggerConfig.userFilterEnabled', action.triggerConfig.userFilterEnabled) }]"
>
<span>启用用户过滤:</span>
<NSwitch v-model:value="action.triggerConfig.userFilterEnabled" />
@@ -97,7 +98,7 @@ const customJsModified = computed(() => {
align="center"
justify="space-between"
style="width: 100%"
:class="['setting-item', {'setting-modified': isModified('triggerConfig.requireMedal', action.triggerConfig.requireMedal)}]"
class="setting-item" :class="[{ 'setting-modified': isModified('triggerConfig.requireMedal', action.triggerConfig.requireMedal) }]"
>
<span>要求本房间勋章:</span>
<NSwitch v-model:value="action.triggerConfig.requireMedal" />
@@ -108,7 +109,7 @@ const customJsModified = computed(() => {
align="center"
justify="space-between"
style="width: 100%"
:class="['setting-item', {'setting-modified': isModified('triggerConfig.requireCaptain', action.triggerConfig.requireCaptain)}]"
class="setting-item" :class="[{ 'setting-modified': isModified('triggerConfig.requireCaptain', action.triggerConfig.requireCaptain) }]"
>
<span>要求任意舰长:</span>
<NSwitch v-model:value="action.triggerConfig.requireCaptain" />
@@ -123,7 +124,7 @@ const customJsModified = computed(() => {
:title="cooldownModified ? '冷却控制 *' : '冷却控制'"
:title-extra="cooldownModified ? '已修改' : ''"
class="settings-section"
:class="{'section-modified': cooldownModified}"
:class="{ 'section-modified': cooldownModified }"
>
<div>
<NSpace
@@ -131,7 +132,7 @@ const customJsModified = computed(() => {
align="center"
justify="space-between"
style="width: 100%"
:class="['setting-item', {'setting-modified': isModified('ignoreCooldown', action.ignoreCooldown)}]"
class="setting-item" :class="[{ 'setting-modified': isModified('ignoreCooldown', action.ignoreCooldown) }]"
>
<span>忽略全局冷却:</span>
<NSwitch v-model:value="action.ignoreCooldown" />
@@ -142,7 +143,7 @@ const customJsModified = computed(() => {
align="center"
justify="space-between"
style="width: 100%"
:class="['setting-item', {'setting-modified': isModified('actionConfig.delaySeconds', action.actionConfig.delaySeconds)}]"
class="setting-item" :class="[{ 'setting-modified': isModified('actionConfig.delaySeconds', action.actionConfig.delaySeconds) }]"
>
<span>延迟执行():</span>
<NInputNumber
@@ -158,7 +159,7 @@ const customJsModified = computed(() => {
align="center"
justify="space-between"
style="width: 100%"
:class="['setting-item', {'setting-modified': isModified('actionConfig.cooldownSeconds', action.actionConfig.cooldownSeconds)}]"
class="setting-item" :class="[{ 'setting-modified': isModified('actionConfig.cooldownSeconds', action.actionConfig.cooldownSeconds) }]"
>
<span>冷却时间():</span>
<NInputNumber
@@ -176,7 +177,7 @@ const customJsModified = computed(() => {
:title="logicalExpressionModified ? '逻辑条件表达式 *' : '逻辑条件表达式'"
:title-extra="logicalExpressionModified ? '已修改' : ''"
class="settings-section"
:class="{'section-modified': logicalExpressionModified}"
:class="{ 'section-modified': logicalExpressionModified }"
>
<div>
<NSpace vertical>
@@ -188,7 +189,7 @@ const customJsModified = computed(() => {
type="textarea"
placeholder="输入表达式,留空则始终为真"
:autosize="{ minRows: 2, maxRows: 5 }"
:class="{'input-modified': isModified('logicalExpression', action.logicalExpression)}"
:class="{ 'input-modified': isModified('logicalExpression', action.logicalExpression) }"
/>
</NSpace>
</div>
@@ -199,7 +200,7 @@ const customJsModified = computed(() => {
:title="customJsModified ? '自定义JS执行 *' : '自定义JS执行'"
:title-extra="customJsModified ? '已修改' : ''"
class="settings-section"
:class="{'section-modified': customJsModified}"
:class="{ 'section-modified': customJsModified }"
>
<div>
<NSpace vertical>
@@ -211,7 +212,7 @@ const customJsModified = computed(() => {
type="textarea"
placeholder="输入要执行的JS代码"
:autosize="{ minRows: 3, maxRows: 8 }"
:class="{'input-modified': isModified('executeCommand', action.executeCommand)}"
:class="{ 'input-modified': isModified('executeCommand', action.executeCommand) }"
/>
</NSpace>
</div>

View File

@@ -1,21 +1,22 @@
<script setup lang="ts">
import { NSpace, NInput, NSwitch, NSelect } from 'naive-ui';
import { AutoActionItem, TriggerType, ActionType, Priority } from '@/client/store/useAutoAction';
import type { AutoActionItem } from '@/client/store/useAutoAction'
import { NInput, NSelect, NSpace, NSwitch } from 'naive-ui'
import { ActionType, Priority, TriggerType } from '@/client/store/useAutoAction'
const props = defineProps({
action: {
type: Object as () => AutoActionItem,
required: true
required: true,
},
hideName: {
type: Boolean,
default: false
default: false,
},
hideEnabled: {
type: Boolean,
default: false
}
});
default: false,
},
})
// 触发类型选项
const triggerTypeOptions = [
@@ -26,14 +27,14 @@ const triggerTypeOptions = [
{ label: '入场欢迎', value: TriggerType.ENTER },
{ label: '定时发送', value: TriggerType.SCHEDULED },
{ label: 'SC感谢', value: TriggerType.SUPER_CHAT },
];
]
// 操作类型选项
const actionTypeOptions = [
{ label: '发送弹幕', value: ActionType.SEND_DANMAKU },
{ label: '发送私信', value: ActionType.SEND_PRIVATE_MSG },
{ label: '执行命令', value: ActionType.EXECUTE_COMMAND },
];
]
// 优先级选项
const priorityOptions = [
@@ -42,7 +43,7 @@ const priorityOptions = [
{ label: '普通', value: Priority.NORMAL },
{ label: '低', value: Priority.LOW },
{ label: '最低', value: Priority.LOWEST },
];
]
</script>
<template>

View File

@@ -1,3 +1,425 @@
<script lang="ts" setup>
import type { DataTableColumns } from 'naive-ui'
import type { CheckInRankingInfo, CheckInResult } from '@/api/api-models'
import { Info24Filled } from '@vicons/fluent'
import { NAlert, NButton, NCard, NDataTable, NDivider, NForm, NFormItem, NIcon, NInput, NInputGroup, NInputNumber, NPopconfirm, NSelect, NSpace, NSpin, NSwitch, NTabPane, NTabs, NText, NTime, NTooltip } from 'naive-ui'
import { computed, h, onMounted, ref } from 'vue'
import { SaveEnableFunctions, SaveSetting, useAccount } from '@/api/account'
import { FunctionTypes } from '@/api/api-models'
import { QueryGetAPI } from '@/api/query'
import { useAutoAction } from '@/client/store/useAutoAction'
import { CHECKIN_API_URL } from '@/data/constants'
import AutoActionEditor from '../AutoActionEditor.vue'
import TemplateHelper from '../TemplateHelper.vue'
interface LiveInfo {
roomId?: number
}
const autoActionStore = useAutoAction()
const config = autoActionStore.checkInModule.checkInConfig
const accountInfo = useAccount()
const isLoading = ref(false)
const customTestContext = ref({
checkin: {
points: 0,
consecutiveDays: 0,
todayRank: 0,
time: new Date(),
},
})
// 签到模板的特定占位符
const checkInPlaceholders = [
{ name: '{{checkin.points}}', description: '获得的总积分' },
{ name: '{{checkin.consecutiveDays}}', description: '连续签到天数' },
{ name: '{{checkin.todayRank}}', description: '今日签到排名' },
{ name: '{{checkin.time}}', description: '签到时间对象' },
]
// 服务端签到设置
const serverSetting = computed(() => {
return accountInfo.value?.settings?.point || {}
})
// 是否可以编辑设置
const canEdit = computed(() => {
return accountInfo.value && accountInfo.value.settings && accountInfo.value.settings.point
})
// 更新所有设置
async function updateSettings() {
// 先保存服务端设置
const serverSaved = await updateServerSettings()
if (serverSaved) {
window.$notification.success({
title: '设置已保存',
duration: 3000,
})
}
return serverSaved
}
// 更新服务端签到设置
async function updateServerSettings() {
if (!canEdit.value) {
return false
}
isLoading.value = true
try {
const msg = await SaveSetting('Point', accountInfo.value.settings.point)
if (msg) {
return true
} else {
window.$notification.error({
title: '保存失败',
content: msg,
duration: 5000,
})
}
} catch (err) {
window.$notification.error({
title: '保存失败',
content: String(err),
duration: 5000,
})
console.error('保存签到设置失败:', err)
} finally {
isLoading.value = false
}
return false
}
// 排行榜数据
const rankingData = ref<CheckInRankingInfo[]>([])
const isLoadingRanking = ref(false)
const timeRange = ref<string>('all')
const userFilter = ref<string>('')
const pagination = ref({
page: 1,
pageSize: 10,
})
// 时间段选项
const timeRangeOptions = [
{ label: '全部时间', value: 'all' },
{ label: '今日', value: 'today' },
{ label: '本周', value: 'week' },
{ label: '本月', value: 'month' },
{ label: '上个月', value: 'lastMonth' },
]
// 过滤后的排行榜数据
const filteredRankingData = computed(() => {
let filtered = rankingData.value
// 按时间范围筛选
if (timeRange.value !== 'all') {
const now = new Date()
let startTime: Date
if (timeRange.value === 'today') {
// 今天凌晨
startTime = new Date(now)
startTime.setHours(0, 0, 0, 0)
} else if (timeRange.value === 'week') {
// 本周一
const dayOfWeek = now.getDay() || 7 // 把周日作为7处理
startTime = new Date(now)
startTime.setDate(now.getDate() - (dayOfWeek - 1))
startTime.setHours(0, 0, 0, 0)
} else if (timeRange.value === 'month') {
// 本月1号
startTime = new Date(now.getFullYear(), now.getMonth(), 1)
} else if (timeRange.value === 'lastMonth') {
// 上月1号
startTime = new Date(now.getFullYear(), now.getMonth() - 1, 1)
// 本月1号作为结束时间
const endTime = new Date(now.getFullYear(), now.getMonth(), 1)
filtered = filtered.filter((user) => {
const checkInTime = new Date(user.lastCheckInTime)
return checkInTime >= startTime && checkInTime < endTime
})
// 已经筛选完成,不需要再次筛选
startTime = new Date(0)
}
// 如果不是上个月,用通用筛选逻辑
if (timeRange.value !== 'lastMonth') {
filtered = filtered.filter((user) => {
const checkInTime = new Date(user.lastCheckInTime)
return checkInTime >= startTime
})
}
}
// 按用户名筛选
if (userFilter.value) {
const keyword = userFilter.value.toLowerCase()
filtered = filtered.filter(user =>
user.name.toLowerCase().includes(keyword),
)
}
return filtered
})
// 排行榜列定义
const rankingColumns: DataTableColumns<CheckInRankingInfo> = [
{
title: '排名',
key: 'rank',
render: (row: CheckInRankingInfo, index: number) => h('span', {}, index + 1),
},
{
title: '用户名',
key: 'name',
},
{
title: '连续签到天数',
key: 'consecutiveDays',
sorter: 'default',
},
{
title: '积分',
key: 'points',
sorter: 'default',
},
{
title: '最近签到时间',
key: 'lastCheckInTime',
render(row: CheckInRankingInfo) {
return h(NTooltip, {
}, {
trigger: () => h(NTime, {
time: row.lastCheckInTime,
type: 'relative',
}),
default: () => new Date(row.lastCheckInTime).toLocaleString(),
})
},
sorter: 'default',
},
{
title: '已认证',
key: 'isAuthed',
render(row: CheckInRankingInfo) {
return h('span', {}, row.isAuthed ? '是' : '否')
},
},
{
title: '操作',
key: 'actions',
render(row: CheckInRankingInfo) {
return h(
NPopconfirm,
{
onPositiveClick: () => resetUserCheckInByGuid(row.ouId),
},
{
trigger: () => h(
NButton,
{
size: 'small',
type: 'warning',
disabled: isResetting.value,
loading: isResetting.value && resetTargetId.value === row.ouId,
onClick: e => e.stopPropagation(),
},
{ default: () => '重置签到' },
),
default: () => '确定要重置该用户的所有签到数据吗?此操作不可撤销。',
},
)
},
},
]
// 加载签到排行榜数据
async function loadCheckInRanking() {
if (isLoadingRanking.value) return
isLoadingRanking.value = true
try {
// 获取所有用户数据,不再根据时间范围过滤
const response = await QueryGetAPI<CheckInRankingInfo[]>(`${CHECKIN_API_URL}admin/users`)
if (response.code == 200) {
rankingData.value = response.data
pagination.value.page = 1 // 重置为第一页
} else {
rankingData.value = []
window.$message.error(`获取签到排行榜失败: ${response.message}`)
}
} catch (error) {
console.error('加载签到排行榜失败:', error)
window.$notification.error({
title: '加载失败',
content: '无法加载签到排行榜数据',
duration: 5000,
})
rankingData.value = []
} finally {
isLoadingRanking.value = false
}
}
// 重置签到数据相关
const isResetting = ref(false)
const resetTargetId = ref<string>()
// 重置单个用户签到数据
async function resetUserCheckInByGuid(ouId: string) {
if (!ouId || isResetting.value) return
isResetting.value = true
resetTargetId.value = ouId
try {
const response = await QueryGetAPI(`${CHECKIN_API_URL}admin/reset`, {
ouId,
})
if (response && response.code === 200) {
window.$notification.success({
title: '重置成功',
content: '用户签到数据已重置',
duration: 3000,
})
// 重置成功后重新加载排行榜
await loadCheckInRanking()
} else {
window.$notification.error({
title: '重置失败',
content: response?.message || '无法重置用户签到数据',
duration: 5000,
})
}
} catch (error) {
console.error('重置用户签到数据失败:', error)
window.$notification.error({
title: '重置失败',
content: '重置用户签到数据时发生错误',
duration: 5000,
})
} finally {
isResetting.value = false
resetTargetId.value = undefined
}
}
// 重置所有用户签到数据
async function resetAllCheckIn() {
if (isResetting.value) return
isResetting.value = true
try {
const response = await QueryGetAPI(`${CHECKIN_API_URL}admin/reset`, {})
if (response && response.code === 200) {
window.$notification.success({
title: '重置成功',
content: '所有用户的签到数据已重置',
duration: 3000,
})
// 重置成功后重新加载排行榜
await loadCheckInRanking()
} else {
window.$notification.error({
title: '重置失败',
content: response?.message || '无法重置所有用户签到数据',
duration: 5000,
})
}
} catch (error) {
console.error('重置所有用户签到数据失败:', error)
window.$notification.error({
title: '重置失败',
content: '重置所有用户签到数据时发生错误',
duration: 5000,
})
} finally {
isResetting.value = false
}
}
// 测试签到功能
const testUid = ref<number>()
const testUsername = ref<string>('测试用户')
const testResult = ref<{ success: boolean, message: string }>()
// 处理测试签到
async function handleTestCheckIn() {
if (!testUid.value || !serverSetting.value.enableCheckIn) {
testResult.value = {
success: false,
message: '请输入有效的UID或确保签到功能已启用',
}
return
}
try {
// 直接调用服务端签到API
const response = await QueryGetAPI<CheckInResult>(`${CHECKIN_API_URL}check-in-for`, {
uId: testUid.value,
name: testUsername.value || '测试用户',
})
if (response.code === 200 && response.data) {
const result = response.data
testResult.value = {
success: result.success,
message: result.success
? `签到成功!用户 ${testUsername.value || '测试用户'} 获得 ${result.points} 积分,连续签到 ${result.consecutiveDays}`
: result.message || '签到失败,可能今天已经签到过了',
}
// 显示通知
window.$notification[result.success ? 'success' : 'info']({
title: result.success ? '测试签到成功' : '测试签到失败',
content: testResult.value.message,
duration: 3000,
})
} else {
testResult.value = {
success: false,
message: `API返回错误: ${response.message || '未知错误'}`,
}
}
} catch (error) {
testResult.value = {
success: false,
message: `签到操作失败: ${error instanceof Error ? error.message : String(error)}`,
}
// 显示错误通知
window.$notification.error({
title: '测试签到失败',
content: testResult.value.message,
duration: 5000,
})
}
}
function updateCheckInRanking(value: boolean) {
accountInfo.value.settings.enableFunctions = value ? [...accountInfo.value.settings.enableFunctions, FunctionTypes.CheckInRanking] : accountInfo.value.settings.enableFunctions.filter(f => f !== FunctionTypes.CheckInRanking)
SaveEnableFunctions(accountInfo.value.settings.enableFunctions)
}
// 组件挂载时加载排行榜
onMounted(() => {
loadCheckInRanking()
})
</script>
<template>
<NCard
v-if="config"
@@ -24,7 +446,7 @@
label-placement="left"
:label-width="120"
:style="{
maxWidth: '650px'
maxWidth: '650px',
}"
>
<!-- 服务端签到设置 -->
@@ -272,7 +694,7 @@
showSizePicker: true,
pageSizes: [10, 20, 50, 100],
onChange: (page: number) => pagination.page = page,
onUpdatePageSize: (pageSize: number) => pagination.pageSize = pageSize
onUpdatePageSize: (pageSize: number) => pagination.pageSize = pageSize,
}"
:bordered="false"
:loading="isLoadingRanking"
@@ -380,428 +802,6 @@
</NCard>
</template>
<script lang="ts" setup>
import { SaveEnableFunctions, SaveSetting, useAccount } from '@/api/account';
import { CheckInRankingInfo, CheckInResult, FunctionTypes } from '@/api/api-models';
import { QueryGetAPI } from '@/api/query';
import { useAutoAction } from '@/client/store/useAutoAction';
import { CHECKIN_API_URL } from '@/data/constants';
import { GuidUtils } from '@/Utils';
import { Info24Filled } from '@vicons/fluent';
import type { DataTableColumns } from 'naive-ui';
import { NAlert, NButton, NCard, NDataTable, NDivider, NEmpty, NForm, NFormItem, NIcon, NInput, NInputGroup, NInputNumber, NPopconfirm, NSelect, NSpace, NSpin, NSwitch, NTabPane, NTabs, NText, NTime, NTooltip } from 'naive-ui';
import { computed, h, onMounted, ref, watch } from 'vue';
import AutoActionEditor from '../AutoActionEditor.vue';
import TemplateHelper from '../TemplateHelper.vue';
interface LiveInfo {
roomId?: number;
}
const autoActionStore = useAutoAction();
const config = autoActionStore.checkInModule.checkInConfig;
const accountInfo = useAccount();
const isLoading = ref(false);
const customTestContext = ref({
checkin: {
points: 0,
consecutiveDays: 0,
todayRank: 0,
time: new Date()
}
});
// 签到模板的特定占位符
const checkInPlaceholders = [
{ name: '{{checkin.points}}', description: '获得的总积分' },
{ name: '{{checkin.consecutiveDays}}', description: '连续签到天数' },
{ name: '{{checkin.todayRank}}', description: '今日签到排名' },
{ name: '{{checkin.time}}', description: '签到时间对象' }
];
// 服务端签到设置
const serverSetting = computed(() => {
return accountInfo.value?.settings?.point || {};
});
// 是否可以编辑设置
const canEdit = computed(() => {
return accountInfo.value && accountInfo.value.settings && accountInfo.value.settings.point;
});
// 更新所有设置
async function updateSettings() {
// 先保存服务端设置
const serverSaved = await updateServerSettings();
if (serverSaved) {
window.$notification.success({
title: '设置已保存',
duration: 3000
});
}
return serverSaved;
}
// 更新服务端签到设置
async function updateServerSettings() {
if (!canEdit.value) {
return false;
}
isLoading.value = true;
try {
const msg = await SaveSetting('Point', accountInfo.value.settings.point);
if (msg) {
return true;
} else {
window.$notification.error({
title: '保存失败',
content: msg,
duration: 5000
});
}
} catch (err) {
window.$notification.error({
title: '保存失败',
content: String(err),
duration: 5000
});
console.error('保存签到设置失败:', err);
} finally {
isLoading.value = false;
}
return false;
}
// 排行榜数据
const rankingData = ref<CheckInRankingInfo[]>([]);
const isLoadingRanking = ref(false);
const timeRange = ref<string>('all');
const userFilter = ref<string>('');
const pagination = ref({
page: 1,
pageSize: 10
});
// 时间段选项
const timeRangeOptions = [
{ label: '全部时间', value: 'all' },
{ label: '今日', value: 'today' },
{ label: '本周', value: 'week' },
{ label: '本月', value: 'month' },
{ label: '上个月', value: 'lastMonth' },
];
// 过滤后的排行榜数据
const filteredRankingData = computed(() => {
let filtered = rankingData.value;
// 按时间范围筛选
if (timeRange.value !== 'all') {
const now = new Date();
let startTime: Date;
if (timeRange.value === 'today') {
// 今天凌晨
startTime = new Date(now);
startTime.setHours(0, 0, 0, 0);
} else if (timeRange.value === 'week') {
// 本周一
const dayOfWeek = now.getDay() || 7; // 把周日作为7处理
startTime = new Date(now);
startTime.setDate(now.getDate() - (dayOfWeek - 1));
startTime.setHours(0, 0, 0, 0);
} else if (timeRange.value === 'month') {
// 本月1号
startTime = new Date(now.getFullYear(), now.getMonth(), 1);
} else if (timeRange.value === 'lastMonth') {
// 上月1号
startTime = new Date(now.getFullYear(), now.getMonth() - 1, 1);
// 本月1号作为结束时间
const endTime = new Date(now.getFullYear(), now.getMonth(), 1);
filtered = filtered.filter(user => {
const checkInTime = new Date(user.lastCheckInTime);
return checkInTime >= startTime && checkInTime < endTime;
});
// 已经筛选完成,不需要再次筛选
startTime = new Date(0);
}
// 如果不是上个月,用通用筛选逻辑
if (timeRange.value !== 'lastMonth') {
filtered = filtered.filter(user => {
const checkInTime = new Date(user.lastCheckInTime);
return checkInTime >= startTime;
});
}
}
// 按用户名筛选
if (userFilter.value) {
const keyword = userFilter.value.toLowerCase();
filtered = filtered.filter(user =>
user.name.toLowerCase().includes(keyword)
);
}
return filtered;
});
// 排行榜列定义
const rankingColumns: DataTableColumns<CheckInRankingInfo> = [
{
title: '排名',
key: 'rank',
render: (row: CheckInRankingInfo, index: number) => h('span', {}, index + 1)
},
{
title: '用户名',
key: 'name'
},
{
title: '连续签到天数',
key: 'consecutiveDays',
sorter: 'default'
},
{
title: '积分',
key: 'points',
sorter: 'default'
},
{
title: '最近签到时间',
key: 'lastCheckInTime',
render(row: CheckInRankingInfo) {
return h(NTooltip, {
}, {
trigger: () => h(NTime, {
time: row.lastCheckInTime,
type: 'relative'
}),
default: () => new Date(row.lastCheckInTime).toLocaleString()
});
},
sorter: 'default'
},
{
title: '已认证',
key: 'isAuthed',
render(row: CheckInRankingInfo) {
return h('span', {}, row.isAuthed ? '是' : '否');
}
},
{
title: '操作',
key: 'actions',
render(row: CheckInRankingInfo) {
return h(
NPopconfirm,
{
onPositiveClick: () => resetUserCheckInByGuid(row.ouId)
},
{
trigger: () => h(
NButton,
{
size: 'small',
type: 'warning',
disabled: isResetting.value,
loading: isResetting.value && resetTargetId.value === row.ouId,
onClick: (e) => e.stopPropagation()
},
{ default: () => '重置签到' }
),
default: () => '确定要重置该用户的所有签到数据吗?此操作不可撤销。'
}
);
}
}
];
// 加载签到排行榜数据
async function loadCheckInRanking() {
if (isLoadingRanking.value) return;
isLoadingRanking.value = true;
try {
// 获取所有用户数据,不再根据时间范围过滤
const response = await QueryGetAPI<CheckInRankingInfo[]>(`${CHECKIN_API_URL}admin/users`);
if (response.code == 200) {
rankingData.value = response.data;
pagination.value.page = 1; // 重置为第一页
} else {
rankingData.value = [];
window.$message.error(`获取签到排行榜失败: ${response.message}`);
}
} catch (error) {
console.error('加载签到排行榜失败:', error);
window.$notification.error({
title: '加载失败',
content: '无法加载签到排行榜数据',
duration: 5000
});
rankingData.value = [];
} finally {
isLoadingRanking.value = false;
}
}
// 重置签到数据相关
const isResetting = ref(false);
const resetTargetId = ref<string>();
// 重置单个用户签到数据
async function resetUserCheckInByGuid(ouId: string) {
if (!ouId || isResetting.value) return;
isResetting.value = true;
resetTargetId.value = ouId;
try {
const response = await QueryGetAPI(`${CHECKIN_API_URL}admin/reset`, {
ouId: ouId
});
if (response && response.code === 200) {
window.$notification.success({
title: '重置成功',
content: '用户签到数据已重置',
duration: 3000
});
// 重置成功后重新加载排行榜
await loadCheckInRanking();
} else {
window.$notification.error({
title: '重置失败',
content: response?.message || '无法重置用户签到数据',
duration: 5000
});
}
} catch (error) {
console.error('重置用户签到数据失败:', error);
window.$notification.error({
title: '重置失败',
content: '重置用户签到数据时发生错误',
duration: 5000
});
} finally {
isResetting.value = false;
resetTargetId.value = undefined;
}
}
// 重置所有用户签到数据
async function resetAllCheckIn() {
if (isResetting.value) return;
isResetting.value = true;
try {
const response = await QueryGetAPI(`${CHECKIN_API_URL}admin/reset`, {});
if (response && response.code === 200) {
window.$notification.success({
title: '重置成功',
content: '所有用户的签到数据已重置',
duration: 3000
});
// 重置成功后重新加载排行榜
await loadCheckInRanking();
} else {
window.$notification.error({
title: '重置失败',
content: response?.message || '无法重置所有用户签到数据',
duration: 5000
});
}
} catch (error) {
console.error('重置所有用户签到数据失败:', error);
window.$notification.error({
title: '重置失败',
content: '重置所有用户签到数据时发生错误',
duration: 5000
});
} finally {
isResetting.value = false;
}
}
// 测试签到功能
const testUid = ref<number>();
const testUsername = ref<string>('测试用户');
const testResult = ref<{ success: boolean; message: string }>();
// 处理测试签到
async function handleTestCheckIn() {
if (!testUid.value || !serverSetting.value.enableCheckIn) {
testResult.value = {
success: false,
message: '请输入有效的UID或确保签到功能已启用'
};
return;
}
try {
// 直接调用服务端签到API
const response = await QueryGetAPI<CheckInResult>(`${CHECKIN_API_URL}check-in-for`, {
uId: testUid.value,
name: testUsername.value || '测试用户'
});
if (response.code === 200 && response.data) {
const result = response.data;
testResult.value = {
success: result.success,
message: result.success
? `签到成功!用户 ${testUsername.value || '测试用户'} 获得 ${result.points} 积分,连续签到 ${result.consecutiveDays}`
: result.message || '签到失败,可能今天已经签到过了'
};
// 显示通知
window.$notification[result.success ? 'success' : 'info']({
title: result.success ? '测试签到成功' : '测试签到失败',
content: testResult.value.message,
duration: 3000
});
} else {
testResult.value = {
success: false,
message: `API返回错误: ${response.message || '未知错误'}`
};
}
} catch (error) {
testResult.value = {
success: false,
message: `签到操作失败: ${error instanceof Error ? error.message : String(error)}`
};
// 显示错误通知
window.$notification.error({
title: '测试签到失败',
content: testResult.value.message,
duration: 5000
});
}
}
function updateCheckInRanking(value: boolean) {
accountInfo.value.settings.enableFunctions = value ? [...accountInfo.value.settings.enableFunctions, FunctionTypes.CheckInRanking] : accountInfo.value.settings.enableFunctions.filter(f => f !== FunctionTypes.CheckInRanking);
SaveEnableFunctions(accountInfo.value.settings.enableFunctions);
}
// 组件挂载时加载排行榜
onMounted(() => {
loadCheckInRanking();
});
</script>
<style scoped>
.settings-section {
margin: 8px 0;
@@ -810,4 +810,4 @@ onMounted(() => {
.ranking-filter {
margin: 10px 0;
}
</style>
</style>

View File

@@ -1,75 +1,75 @@
<script setup lang="ts">
import { ref } from 'vue';
import { NSpace, NInput, NButton, NTag, NDivider, NCollapseItem, useMessage, NRadioGroup, NRadioButton } from 'naive-ui';
import { AutoActionItem, TriggerType } from '@/client/store/useAutoAction';
import { KeywordMatchType } from '@/client/store/autoAction/types';
import SingleTemplateEditor from '../SingleTemplateEditor.vue';
import type { AutoActionItem } from '@/client/store/useAutoAction'
import { NButton, NCollapseItem, NDivider, NInput, NRadioButton, NRadioGroup, NSpace, NTag, useMessage } from 'naive-ui'
import { ref } from 'vue'
import { KeywordMatchType } from '@/client/store/autoAction/types'
import { TriggerType } from '@/client/store/useAutoAction'
const props = defineProps({
action: {
type: Object as () => AutoActionItem,
required: true
}
});
required: true,
},
})
const message = useMessage();
const message = useMessage()
// 弹幕关键词相关
const tempKeyword = ref('');
const tempBlockword = ref('');
const tempKeyword = ref('')
const tempBlockword = ref('')
// 初始化匹配类型配置
if (!props.action.triggerConfig.keywordMatchType) {
props.action.triggerConfig.keywordMatchType = KeywordMatchType.Contains;
props.action.triggerConfig.keywordMatchType = KeywordMatchType.Contains
}
if (!props.action.triggerConfig.blockwordMatchType) {
props.action.triggerConfig.blockwordMatchType = KeywordMatchType.Contains;
props.action.triggerConfig.blockwordMatchType = KeywordMatchType.Contains
}
// 添加关键词
function addKeyword() {
if (!tempKeyword.value.trim()) return;
if (!tempKeyword.value.trim()) return
if (!props.action.triggerConfig.keywords) {
props.action.triggerConfig.keywords = [];
props.action.triggerConfig.keywords = []
}
if (!props.action.triggerConfig.keywords.includes(tempKeyword.value.trim())) {
props.action.triggerConfig.keywords.push(tempKeyword.value.trim());
tempKeyword.value = '';
props.action.triggerConfig.keywords.push(tempKeyword.value.trim())
tempKeyword.value = ''
} else {
message.warning('此关键词已存在');
message.warning('此关键词已存在')
}
}
// 移除关键词
function removeKeyword(index: number) {
if (props.action.triggerConfig.keywords) {
props.action.triggerConfig.keywords.splice(index, 1);
props.action.triggerConfig.keywords.splice(index, 1)
}
}
// 添加屏蔽词
function addBlockword() {
if (!tempBlockword.value.trim()) return;
if (!tempBlockword.value.trim()) return
if (!props.action.triggerConfig.blockwords) {
props.action.triggerConfig.blockwords = [];
props.action.triggerConfig.blockwords = []
}
if (!props.action.triggerConfig.blockwords.includes(tempBlockword.value.trim())) {
props.action.triggerConfig.blockwords.push(tempBlockword.value.trim());
tempBlockword.value = '';
props.action.triggerConfig.blockwords.push(tempBlockword.value.trim())
tempBlockword.value = ''
} else {
message.warning('此屏蔽词已存在');
message.warning('此屏蔽词已存在')
}
}
// 移除屏蔽词
function removeBlockword(index: number) {
if (props.action.triggerConfig.blockwords) {
props.action.triggerConfig.blockwords.splice(index, 1);
props.action.triggerConfig.blockwords.splice(index, 1)
}
}
@@ -82,7 +82,7 @@ const danmakuPlaceholders = [
{ name: '{{user.medalName}}', description: '粉丝勋章名称' },
{ name: '{{message}}', description: '弹幕内容' },
{ name: '{{js: message.substring(0, 10)}}', description: '弹幕内容的前10个字符' },
];
]
</script>
<template>

View File

@@ -1,13 +1,14 @@
<script setup lang="ts">
import { NSpace, NSwitch, NInputNumber, NSelect, NCollapseItem } from 'naive-ui';
import { AutoActionItem, TriggerType } from '@/client/store/useAutoAction';
import type { AutoActionItem } from '@/client/store/useAutoAction'
import { NCollapseItem, NInputNumber, NSelect, NSpace, NSwitch } from 'naive-ui'
import { TriggerType } from '@/client/store/useAutoAction'
const props = defineProps({
action: {
type: Object as () => AutoActionItem,
required: true
}
});
required: true,
},
})
// 入场过滤模式选项
const enterFilterModeOptions = [
@@ -15,8 +16,8 @@ const enterFilterModeOptions = [
{ label: '用户黑名单', value: 'blacklist' },
{ label: '用户白名单', value: 'whitelist' },
{ label: '仅舰长', value: 'guard' },
{ label: '仅勋章', value: 'medal' }
];
{ label: '仅勋章', value: 'medal' },
]
</script>
<template>
@@ -62,4 +63,4 @@ const enterFilterModeOptions = [
</NSpace>
</NSpace>
</NCollapseItem>
</template>
</template>

View File

@@ -1,13 +1,14 @@
<script setup lang="ts">
import { NSpace, NSwitch, NInputNumber, NCollapseItem } from 'naive-ui';
import { AutoActionItem, TriggerType } from '@/client/store/useAutoAction';
import type { AutoActionItem } from '@/client/store/useAutoAction'
import { NCollapseItem, NInputNumber, NSpace, NSwitch } from 'naive-ui'
import { TriggerType } from '@/client/store/useAutoAction'
const props = defineProps({
action: {
type: Object as () => AutoActionItem,
required: true
}
});
required: true,
},
})
</script>
<template>
@@ -40,4 +41,4 @@ const props = defineProps({
</NSpace>
</NSpace>
</NCollapseItem>
</template>
</template>

View File

@@ -1,16 +1,17 @@
<script setup lang="ts">
import { ref } from 'vue';
import { NSpace, NInput, NButton, NTag, NSelect, NInputNumber, NSwitch, NCollapseItem, useMessage } from 'naive-ui';
import { AutoActionItem, TriggerType } from '@/client/store/useAutoAction';
import type { AutoActionItem } from '@/client/store/useAutoAction'
import { NButton, NCollapseItem, NInput, NInputNumber, NSelect, NSpace, NSwitch, NTag, useMessage } from 'naive-ui'
import { ref } from 'vue'
import { TriggerType } from '@/client/store/useAutoAction'
const props = defineProps({
action: {
type: Object as () => AutoActionItem,
required: true
}
});
required: true,
},
})
const message = useMessage();
const message = useMessage()
// 礼物过滤模式选项
const giftFilterModeOptions = [
@@ -18,32 +19,32 @@ const giftFilterModeOptions = [
{ label: '礼物黑名单', value: 'blacklist' },
{ label: '礼物白名单', value: 'whitelist' },
{ label: '最低价值', value: 'value' },
{ label: '过滤免费礼物', value: 'free' }
];
{ label: '过滤免费礼物', value: 'free' },
]
// 礼物名称相关
const tempGiftName = ref('');
const tempGiftName = ref('')
// 添加礼物名称到过滤列表
function addGiftName() {
if (!tempGiftName.value.trim()) return;
if (!tempGiftName.value.trim()) return
if (!props.action.triggerConfig.filterGiftNames) {
props.action.triggerConfig.filterGiftNames = [];
props.action.triggerConfig.filterGiftNames = []
}
if (!props.action.triggerConfig.filterGiftNames.includes(tempGiftName.value.trim())) {
props.action.triggerConfig.filterGiftNames.push(tempGiftName.value.trim());
tempGiftName.value = '';
props.action.triggerConfig.filterGiftNames.push(tempGiftName.value.trim())
tempGiftName.value = ''
} else {
message.warning('此礼物名称已存在');
message.warning('此礼物名称已存在')
}
}
// 移除礼物名称
function removeGiftName(index: number) {
if (props.action.triggerConfig.filterGiftNames) {
props.action.triggerConfig.filterGiftNames.splice(index, 1);
props.action.triggerConfig.filterGiftNames.splice(index, 1)
}
}
</script>

View File

@@ -1,29 +1,28 @@
<script setup lang="ts">
import {
NCard,
NSpace,
NDivider,
NInputNumber,
NRadioGroup,
NRadio,
NRadioGroup,
NSpace,
NText,
NDivider
} from 'naive-ui';
import { useAutoAction } from '@/client/store/useAutoAction';
import { watch } from 'vue';
} from 'naive-ui'
import { watch } from 'vue'
import { useAutoAction } from '@/client/store/useAutoAction'
const autoActionStore = useAutoAction();
const autoActionStore = useAutoAction()
// 定时模式选项
const schedulingModeOptions = [
{ label: '随机模式', value: 'random' },
{ label: '顺序模式', value: 'sequential' }
];
{ label: '顺序模式', value: 'sequential' },
]
// 监听变化,触发定时器重启(如果间隔改变)
watch(() => autoActionStore.globalIntervalSeconds, () => {
autoActionStore.restartGlobalTimer(); // 确保间隔改变时定时器更新
});
autoActionStore.restartGlobalTimer() // 确保间隔改变时定时器更新
})
</script>
<template>
@@ -82,4 +81,4 @@ watch(() => autoActionStore.globalIntervalSeconds, () => {
<style scoped>
/* 可以添加一些特定样式 */
</style>
</style>

View File

@@ -1,57 +1,58 @@
<script setup lang="ts">
import { ref } from 'vue';
import { NSpace, NInput, NButton, NTag, NSelect, NSwitch, NDivider, NCollapseItem, useMessage } from 'naive-ui';
import { AutoActionItem, TriggerType, ActionType } from '@/client/store/useAutoAction';
import type { AutoActionItem } from '@/client/store/useAutoAction'
import { NButton, NCollapseItem, NDivider, NInput, NSelect, NSpace, NSwitch, NTag, useMessage } from 'naive-ui'
import { ref } from 'vue'
import { ActionType, TriggerType } from '@/client/store/useAutoAction'
const props = defineProps({
action: {
type: Object as () => AutoActionItem,
required: true
}
});
required: true,
},
})
const message = useMessage();
const message = useMessage()
// 舰长礼品码相关
const tempGiftCodeLevel = ref(3); // 默认为舰长等级
const tempGiftCode = ref('');
const tempGiftCodeLevel = ref(3) // 默认为舰长等级
const tempGiftCode = ref('')
// 添加礼品码
function addGiftCode() {
if (!tempGiftCode.value.trim()) return;
if (!tempGiftCode.value.trim()) return
if (!props.action.triggerConfig.giftCodes) {
props.action.triggerConfig.giftCodes = [];
props.action.triggerConfig.giftCodes = []
}
// 查找对应等级的礼品码数组
let levelCodes = props.action.triggerConfig.giftCodes.find(gc => gc.level === tempGiftCodeLevel.value);
let levelCodes = props.action.triggerConfig.giftCodes.find(gc => gc.level === tempGiftCodeLevel.value)
if (!levelCodes) {
// 如果没有此等级的礼品码数组,创建一个
levelCodes = { level: tempGiftCodeLevel.value, codes: [] };
props.action.triggerConfig.giftCodes.push(levelCodes);
levelCodes = { level: tempGiftCodeLevel.value, codes: [] }
props.action.triggerConfig.giftCodes.push(levelCodes)
}
// 添加礼品码
if (!levelCodes.codes.includes(tempGiftCode.value.trim())) {
levelCodes.codes.push(tempGiftCode.value.trim());
tempGiftCode.value = '';
levelCodes.codes.push(tempGiftCode.value.trim())
tempGiftCode.value = ''
} else {
message.warning('此礼品码已存在');
message.warning('此礼品码已存在')
}
}
// 移除礼品码
function removeGiftCode(levelIndex: number, codeIndex: number) {
if (props.action.triggerConfig.giftCodes &&
props.action.triggerConfig.giftCodes[levelIndex] &&
props.action.triggerConfig.giftCodes[levelIndex].codes) {
props.action.triggerConfig.giftCodes[levelIndex].codes.splice(codeIndex, 1);
if (props.action.triggerConfig.giftCodes
&& props.action.triggerConfig.giftCodes[levelIndex]
&& props.action.triggerConfig.giftCodes[levelIndex].codes) {
props.action.triggerConfig.giftCodes[levelIndex].codes.splice(codeIndex, 1)
// 如果该等级没有礼品码了,移除这个等级
if (props.action.triggerConfig.giftCodes[levelIndex].codes.length === 0) {
props.action.triggerConfig.giftCodes.splice(levelIndex, 1);
props.action.triggerConfig.giftCodes.splice(levelIndex, 1)
}
}
}
@@ -59,10 +60,10 @@ function removeGiftCode(levelIndex: number, codeIndex: number) {
// 舰长等级名称映射
function getGuardLevelName(level: number): string {
switch (level) {
case 1: return '总督';
case 2: return '提督';
case 3: return '舰长';
default: return '通用';
case 1: return '总督'
case 2: return '提督'
case 3: return '舰长'
default: return '通用'
}
}
</script>
@@ -95,7 +96,7 @@ function getGuardLevelName(level: number): string {
{ label: '总督', value: 1 },
{ label: '提督', value: 2 },
{ label: '舰长', value: 3 },
{ label: '通用', value: 0 }
{ label: '通用', value: 0 },
]"
/>
<NInput

View File

@@ -1,48 +1,48 @@
<script setup lang="ts">
import type { AutoActionItem } from '@/client/store/useAutoAction'
import {
NSpace,
NInputNumber,
NRadioGroup,
NRadio,
NCollapseItem,
NSwitch,
NDivider,
NText
} from 'naive-ui';
import { AutoActionItem, TriggerType } from '@/client/store/useAutoAction';
import { computed, ref, watch } from 'vue';
NInputNumber,
NRadio,
NRadioGroup,
NSpace,
NSwitch,
NText,
} from 'naive-ui'
import { ref, watch } from 'vue'
import { TriggerType } from '@/client/store/useAutoAction'
const props = defineProps({
action: {
type: Object as () => AutoActionItem,
required: true
}
});
required: true,
},
})
// 初始化配置项
if (props.action.triggerConfig.useGlobalTimer === undefined) {
props.action.triggerConfig.useGlobalTimer = false; // 默认不使用全局定时器
props.action.triggerConfig.useGlobalTimer = false // 默认不使用全局定时器
}
if (props.action.triggerConfig.schedulingMode === undefined) {
props.action.triggerConfig.schedulingMode = 'random'; // 默认随机模式
props.action.triggerConfig.schedulingMode = 'random' // 默认随机模式
}
if (props.action.triggerConfig.intervalSeconds === undefined) {
props.action.triggerConfig.intervalSeconds = 300; // 默认5分钟
props.action.triggerConfig.intervalSeconds = 300 // 默认5分钟
}
const useGlobalTimer = ref(props.action.triggerConfig.useGlobalTimer);
const useGlobalTimer = ref(props.action.triggerConfig.useGlobalTimer)
// 同步到 action
watch(useGlobalTimer, (value) => {
props.action.triggerConfig.useGlobalTimer = value;
});
props.action.triggerConfig.useGlobalTimer = value
})
// 定时模式选项
const schedulingModeOptions = [
{ label: '随机模式', value: 'random' },
{ label: '顺序模式', value: 'sequential' }
];
{ label: '顺序模式', value: 'sequential' },
]
</script>
<template>

View File

@@ -1,19 +1,20 @@
<script setup lang="ts">
import { NSpace, NSwitch, NInputNumber, NSelect, NCollapseItem } from 'naive-ui';
import { AutoActionItem, TriggerType } from '@/client/store/useAutoAction';
import type { AutoActionItem } from '@/client/store/useAutoAction'
import { NCollapseItem, NInputNumber, NSelect, NSpace, NSwitch } from 'naive-ui'
import { TriggerType } from '@/client/store/useAutoAction'
const props = defineProps({
action: {
type: Object as () => AutoActionItem,
required: true
}
});
required: true,
},
})
// SC过滤模式选项
const scFilterModeOptions = [
{ label: '不过滤', value: 'none' },
{ label: '最低价格', value: 'price' }
];
{ label: '最低价格', value: 'price' },
]
</script>
<template>
@@ -74,4 +75,4 @@ const scFilterModeOptions = [
</NSpace>
</NSpace>
</NCollapseItem>
</template>
</template>

View File

@@ -1,54 +1,54 @@
<script setup lang="ts">
import { computed } from 'vue';
import { NDivider } from 'naive-ui';
import TemplateEditor from '../TemplateEditor.vue';
import { AutoActionItem, TriggerType, ActionType } from '@/client/store/useAutoAction';
import type { AutoActionItem } from '@/client/store/useAutoAction'
import { computed } from 'vue'
import { ActionType } from '@/client/store/useAutoAction'
import TemplateEditor from '../TemplateEditor.vue'
const props = defineProps({
action: {
type: Object as () => AutoActionItem,
required: true
required: true,
},
customTestContext: {
type: Object,
default: undefined
}
});
default: undefined,
},
})
// 根据操作类型获取模板标题
const templateTitle = computed(() => {
switch (props.action.actionType) {
case ActionType.SEND_DANMAKU:
return '弹幕模板';
return '弹幕模板'
case ActionType.SEND_PRIVATE_MSG:
return '私信模板';
return '私信模板'
case ActionType.EXECUTE_COMMAND:
return '命令模板';
return '命令模板'
default:
return '消息模板';
return '消息模板'
}
});
})
// 根据操作类型获取模板描述
const templateDescription = computed(() => {
switch (props.action.actionType) {
case ActionType.SEND_DANMAKU:
return '发送到直播间的弹幕内容';
return '发送到直播间的弹幕内容'
case ActionType.SEND_PRIVATE_MSG:
return '发送给用户的私信内容';
return '发送给用户的私信内容'
case ActionType.EXECUTE_COMMAND:
return '执行的命令模板';
return '执行的命令模板'
default:
return '消息内容模板';
return '消息内容模板'
}
});
})
// Handle template updates from TemplateEditor
function handleTemplateUpdate(payload: { index: number, value: string }) {
// Assuming index will always be 0 here as we only render one editor
// And assuming action.templates is a string based on previous findings
if (payload.index === 0) {
props.action.template = payload.value;
props.action.template = payload.value
}
}
</script>