feat: init

This commit is contained in:
Rogee
2024-09-30 11:02:26 +08:00
parent 679759846b
commit 694dfd2a4f
90 changed files with 6046 additions and 15 deletions

View File

@@ -0,0 +1,192 @@
<script setup lang="ts">
import axios, { AxiosResponse } from 'axios';
import { onMounted, ref } from 'vue';
interface Device {
ID: number
UUID: string
Name: string
Expert: string
ExpertName: string
State: string
Note: string
}
interface Expert {
ID: number
UID: string
SecUID: string
ShortID: string
RealName: string
NickName: string
State: string
Since: number
Focus: number
Total: number
Voice: string
Hello: string
}
const devices = ref<Device[]>([]);
const experts = ref<Expert[]>([]);
// use axios get /experts onMount
const loadExperts = function () {
axios.get<Expert[]>('/api/experts').then((resp: AxiosResponse) => {
experts.value = resp.data;
});
}
// use axios get /experts onMount
const loadDevices = function () {
axios.get<Device[]>('/api/devices').then((resp: AxiosResponse) => {
devices.value = resp.data;
});
}
onMounted(() => {
loadDevices()
});
setInterval(loadDevices, 30 * 1000);
const currentDevice = ref<Device | null>(null);
const showDeviceUpdateModal = (id: number) => {
loadExperts();
currentDevice.value = devices.value.find((device) => device.ID === id) || null;
selectExpert.value = currentDevice.value?.Expert
deviceName.value = currentDevice.value?.Name
const dialog = document.getElementById("show_device_update_modal") as HTMLDialogElement;
dialog.showModal();
};
const resetStateNormal = (id: number) => {
currentDevice.value = devices.value.find((device) => device.ID === id) || null;
if (!currentDevice.value) {
return;
}
// alert to confirm
if (!confirm(`确定要恢复 ${currentDevice.value.UUID} 的自动关注吗?`)) {
return;
}
const data = { state: "" };
axios.patch(`/api/devices/${currentDevice.value?.UUID}/state`, data).then((resp: AxiosResponse) => {
console.log(resp.data)
loadDevices();
});
};
const setStateStop = (id: number) => {
currentDevice.value = devices.value.find((device) => device.ID === id) || null;
if (!currentDevice.value) {
return;
}
// alert to confirm
if (!confirm(`确定要停止 ${currentDevice.value.UUID} 的自动关注吗?`)) {
return;
}
const data = { state: "stop" };
axios.patch(`/api/devices/${currentDevice.value?.UUID}/state`, data).then((resp: AxiosResponse) => {
console.log(resp.data)
loadDevices();
});
};
const closeModal = function () {
const dialog = document.getElementById("show_device_update_modal") as HTMLDialogElement;
dialog.close();
}
const deviceName = ref<String | null>();
const selectExpert = ref<String | null>();
const saveDate = () => {
const data = {
name: deviceName.value,
};
console.log(data)
axios.patch(`/api/devices/${currentDevice.value?.UUID}/experts/${selectExpert.value}`, data).then((resp: AxiosResponse) => {
console.log(resp.data)
loadDevices();
setTimeout(closeModal, 500)
});
};
</script>
<template>
<dialog id="show_device_update_modal" class="modal">
<div class="modal-box">
<form method="dialog">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
</form>
<h3 class="font-bold text-lg">{{ currentDevice?.UUID }}</h3>
<div class="py-5">
<label class="form-control w-full max-w-xs">
<div class="label">
<span class="label-text">设备名称</span>
</div>
<input type="text" placeholder="设备名称" class="input input-bordered w-full max-w-xs" v-model="deviceName"/>
</label>
<label class="form-control w-full">
<div class="label">
<span class="label-text">选择专家</span>
</div>
<select class="select select-bordered w-full max-w-xs" v-model="selectExpert">
<option v-for="expert in experts" :key="expert.ID" :value="expert.UID">{{ expert.RealName }}</option>
</select>
</label>
</div>
<div class="flex justify-end gap-3">
<button class="btn btn-wide btn-primary" @click="saveDate">保存</button>
</div>
</div>
</dialog>
<div className="overflow-x-auto">
<div v-if="devices.length == 0">
<h1 class="text-lg text-center">还没有设备</h1>
</div>
<table className="table" v-else>
<thead>
<tr>
<th>设备号</th>
<th>名称</th>
<th>专家</th>
<th>停止关注</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr :class='idx % 2 == 1 ? "bg-slate-50" : ""' v-for="(item, idx) in devices" :key="item.ID">
<td class="flex flex-col">
<div class="text-lg font-semibold">{{ item.UUID }}</div>
</td>
<td>{{ item.Name }}</td>
<td>
<button class="btn btn-sm" @click="showDeviceUpdateModal(item.ID)">{{ item.ExpertName }}</button>
</td>
<td>
<button v-if="item.State == 'stop'" class="btn btn-warning btn-sm"
@click="resetStateNormal(item.ID)">恢复</button>
<button v-else class="btn btn-error btn-sm text-white" @click="setStateStop(item.ID)">停止</button>
</td>
<td>{{ item.Note }}</td>
</tr>
</tbody>
</table>
</div>
</template>

View File

@@ -0,0 +1,288 @@
<script setup lang="ts">
import axios, { AxiosResponse } from 'axios';
import moment from 'moment';
import { onMounted, ref } from 'vue';
interface Expert {
ID: number
UID: string
SecUID: string
ShortID: string
RealName: string
NickName: string
State: string
Since: number
Focus: number
Total: number
Conf: Conf
}
interface Conf {
Voice: string
Hello: string
Wechat: string
Region: string[]
NameKeyword: string[]
Produce: boolean
DefaultName: boolean
DefaultAvatar: boolean
}
const experts = ref<Expert[]>([]);
// use axios get /experts onMount
const loadExperts = function () {
axios.get<Expert[]>('/api/experts').then((resp: AxiosResponse) => {
experts.value = resp.data;
});
}
onMounted(loadExperts);
setInterval(loadExperts, 30 * 1000);
const parseTime = function (timestamp: number) {
if (timestamp == 0) {
return '不限制'
}
return moment.unix(timestamp).format('YY/MM/DD HH:mm:ss')
}
const currentExpert = ref<Expert | null>(null);
const showExpertDateModal = (id: number) => {
currentExpert.value = experts.value.find((expert) => expert.ID === id) || null;
date.value = moment.unix(currentExpert.value?.Since || 0).format('YYYY-MM-DDTHH:mm');
voice.value = currentExpert.value?.Conf.Voice || '';
hello.value = currentExpert.value?.Conf.Hello || '';
wechat.value = currentExpert.value?.Conf.Wechat || '';
region.value = (currentExpert.value?.Conf.Region || []).join(',');
produce.value = currentExpert.value?.Conf.Produce || false;
default_name.value = currentExpert.value?.Conf.DefaultName || false;
default_avatar.value = currentExpert.value?.Conf.DefaultAvatar || false;
name_keyword.value = (currentExpert.value?.Conf.NameKeyword || []).join(',');
const dialog = document.getElementById("set_date_modal") as HTMLDialogElement;
dialog.showModal();
};
const resetStateNormal = (id: number) => {
currentExpert.value = experts.value.find((expert) => expert.ID === id) || null;
if (!currentExpert.value) {
return;
}
// alert to confirm
if (!confirm(`确定要恢复 ${currentExpert.value.RealName} 的自动关注吗?`)) {
return;
}
const data = { state: "" };
axios.patch(`/api/experts/${currentExpert.value?.UID}/state`, data).then((resp: AxiosResponse) => {
console.log(resp.data)
loadExperts();
});
};
const setStateStop = (id: number) => {
currentExpert.value = experts.value.find((expert) => expert.ID === id) || null;
if (!currentExpert.value) {
return;
}
// alert to confirm
if (!confirm(`确定要停止 ${currentExpert.value.RealName} 的自动关注吗?`)) {
return;
}
const data = { state: "stop" };
axios.patch(`/api/experts/${currentExpert.value?.UID}/state`, data).then((resp: AxiosResponse) => {
console.log(resp.data)
loadExperts();
});
};
const closeModal = function () {
const dialog = document.getElementById("set_date_modal") as HTMLDialogElement;
dialog.close();
}
const resetDate = () => {
const data = { since: 0 };
axios.patch(`/api/experts/${currentExpert.value?.UID}/config`, data).then((resp: AxiosResponse) => {
console.log(resp.data)
loadExperts();
setTimeout(closeModal, 500)
});
};
const date = ref('2022-02-01T01:10');
const voice = ref('');
const hello = ref('');
const wechat = ref('');
const region = ref('');
const produce = ref(false);
const default_name = ref(false);
const default_avatar = ref(false);
const name_keyword = ref('');
const saveDate = () => {
let regions = region.value.replace(/\s/g, '').replace("", "").split(',');
let name_keywords = name_keyword.value.replace(/\s/g, '').replace("", "").split(',');
const data = {
since: Date.parse(date.value) / 1000,
voice: voice.value,
hello: hello.value,
wechat: wechat.value,
region: regions,
produce: produce.value,
DefaultName: default_name.value,
DefaultAvatar: default_avatar.value,
NameKeyword: name_keywords,
};
console.log(data)
axios.patch(`/api/experts/${currentExpert.value?.UID}/config`, data).then((resp: AxiosResponse) => {
console.log(resp.data)
loadExperts();
setTimeout(closeModal, 500)
});
};
</script>
<template>
<dialog id="set_date_modal" class="modal">
<div class="modal-box">
<form method="dialog">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
</form>
<h3 class="font-bold text-lg">{{ currentExpert?.RealName }}</h3>
<div class="py-5">
<label class="form-control w-full mb-5">
<div class="label">
<span class="label-text">微信号</span>
</div>
<input type="text" placeholder="微信号" class="input input-bordered w-full " v-model="wechat" />
</label>
<label class="form-control w-full mb-5">
<div class="label">
<span class="label-text">语音ID</span>
</div>
<input type="text" placeholder="语音ID" class="input input-bordered w-full " v-model="voice" />
</label>
<label class="form-control w-full " mb-5>
<div class="label">
<span class="label-text">打招呼模板</span>
</div>
<textarea v-model="hello" class="textarea textarea-bordered w-full " placeholder="打招呼模板"></textarea>
</label>
<label class="form-control w-full mb-5">
<div class="label">
<span class="label-text">屏蔽IP区域用户</span>
</div>
<input type="text" placeholder="屏蔽IP区域用户" class="input input-bordered w-full" v-model="region" />
<div class="label">
<span class="label-text-alt">多个区域用 , 号分割</span>
</div>
</label>
<label class="form-control w-full mb-5">
<div class="label">
<span class="label-text">屏蔽用户名关键字</span>
</div>
<input type="text" placeholder="屏蔽用户名关键字" class="input input-bordered w-full" v-model="name_keyword" />
<div class="label">
<span class="label-text-alt">多个用,号分割</span>
</div>
</label>
<label class="form-control w-full ">
<div class="form-control">
<label class="cursor-pointer label justify-start gap-1">
<input type="checkbox" v-model="produce" class="checkbox checkbox-success" />
<span class="label-text">屏蔽0作品用户</span>
</label>
</div>
</label>
<label class="form-control w-full ">
<div class="form-control">
<label class="cursor-pointer label justify-start gap-1">
<input type="checkbox" v-model="default_name" class="checkbox checkbox-success" />
<span class="label-text">屏蔽默认用户名用户</span>
</label>
</div>
</label>
<label class="form-control w-full ">
<div class="form-control">
<label class="cursor-pointer label justify-start gap-1">
<input type="checkbox" v-model="default_avatar" class="checkbox checkbox-success" />
<span class="label-text">屏蔽默认头像名用户</span>
</label>
</div>
</label>
<label class="form-control w-full">
<div class="label">
<span class="label-text">选择时间</span>
</div>
<input type="datetime-local" v-model="date" placeholder="请选择时间" class="input input-bordered w-full" />
<div class="label">
<span class="label-text-alt">获取晚于这个时间关注的粉丝数据</span>
</div>
</label>
</div>
<div class="flex justify-end gap-3">
<button class="btn btn-default" @click="resetDate">恢复不限制</button>
<button class="btn btn-wide btn-primary" @click="saveDate">保存</button>
</div>
</div>
</dialog>
<div className="overflow-x-auto">
<div v-if="experts.length == 0">
<h1 class="text-lg text-center">还没有专家</h1>
</div>
<table className="table" v-else>
<thead>
<tr>
<th>专家</th>
<th>已关注/所有</th>
<th>配置</th>
<th>停止关注</th>
</tr>
</thead>
<tbody>
<tr :class='idx % 2 == 1 ? "bg-slate-50" : ""' v-for="(item, idx) in experts" :key="item.ID">
<td class="flex flex-col">
<div class="text-lg font-semibold">{{ item.RealName }}</div>
<div>{{ item.UID }}</div>
</td>
<td>{{ item.Focus }} / {{ item.Total }}</td>
<td>
<button class="btn btn-sm" @click="showExpertDateModal(item.ID)">{{ parseTime(item.Since) }}</button>
</td>
<td>
<button v-if="item.State == 'stop'" class="btn btn-warning btn-sm"
@click="resetStateNormal(item.ID)">恢复</button>
<button v-else class="btn btn-error btn-sm text-white" @click="setStateStop(item.ID)">停止</button>
</td>
</tr>
</tbody>
</table>
</div>
</template>