This commit is contained in:
Putoo
2026-05-29 19:06:51 +08:00
parent 69ae1e3174
commit bd1535aee9
48 changed files with 1571 additions and 133 deletions

View File

@@ -15,7 +15,7 @@ const { on, emit } = useEventBus()
//连接signlar
const ConnectSignlar = (clientId: string) => {
console.log(`客户端:${clientId}`);
console.log(`客户端:${clientId}`);
}
@@ -48,14 +48,15 @@ onMounted(() => {
ConnectSignlar(payload);
})
})
</script>
<style>
/* 页面级样式可以在这里定义 */
/* 全局样式已移至 src/assets/css/style.css */
:root{
--van-base-font: initial !important;
:root {
--van-base-font: initial !important;
}
</style>

View File

@@ -3,9 +3,13 @@
<div class="item" v-for="(item, index) in data" :key="index">
<span>[{{ GetChatType(item.chat.code) }}]</span>
<span>
<GameUser :data="item.user" :show-icon="1"></GameUser>:
<span>
{{ item.chat.sign }}
<span v-if="item.chat.code == 'System'">
海精灵:
</span>
<span v-if="item.chat.code != 'System'">
<GameUser :data="item.user" :show-icon="1"></GameUser>:
</span>
<span v-html="item.chat.sign" @click="HtmlEvent">
</span>
<span v-if="showTime == 1">
({{ TimeExtend.StrToFormat(item.chat.addTime, "dd日HH:mm") }})

View File

@@ -1,5 +1,8 @@
<template>
<Abar :href='"/user/user?no=" +data.userNo' >{{ data.nick }}</Abar>
<span v-if="data.userNo == '0'">海精灵</span>
<span v-else>
<Abar :href='"/user/user?no=" + data.userNo'>{{ data.nick }}</Abar>
</span>
</template>
<script lang="ts" setup>
const props = defineProps({

View File

@@ -0,0 +1,12 @@
/** Html 富文本事件统一处理(全局自动可用) */
export const HtmlEvent = (e: any) => {
const target = e.target
const type = target.dataset.type
const parms = target.dataset.parms
switch (type) {
case 'go':
navigateTo(parms)
break
}
}

View File

@@ -1,5 +1,9 @@
export class PageExtend {
public static Redirect(route: string) {
navigateTo(route)
}
public static RedirectTo(route: string) {
navigateTo(route, { replace: true })
}

View File

@@ -0,0 +1,43 @@
export class StringExtend {
/**
* 去除字符串【开头和结尾】的指定字符
* @param str 原始字符串
* @param char 要删除的字符(单个)
*/
static trim(str: string | null | undefined, char: string): string {
if (!str) return ''
if (char.length !== 1) return str
const escaped = this.#escapeRegChar(char)
return str.replace(new RegExp(`^${escaped}+|${escaped}+$`, 'g'), '')
}
/**
* 仅去除字符串【开头】的指定字符
*/
static trimStart(str: string | null | undefined, char: string): string {
if (!str) return ''
if (char.length !== 1) return str
const escaped = this.#escapeRegChar(char)
return str.replace(new RegExp(`^${escaped}+`, 'g'), '')
}
/**
* 仅去除字符串【结尾】的指定字符
*/
static trimEnd(str: string | null | undefined, char: string): string {
if (!str) return ''
if (char.length !== 1) return str
const escaped = this.#escapeRegChar(char)
return str.replace(new RegExp(`${escaped}+$`, 'g'), '')
}
/**
* 私有:转义正则特殊字符(. * + ? ^ $ 等)
*/
static #escapeRegChar(char: string): string {
return char.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}
}

View File

@@ -8,6 +8,7 @@ export class TimeExtend {
public static Format(date: Date | string | number, format = 'yyyy-MM-dd HH:mm:ss'): string {
let targetDate: Date
if (typeof date === 'number') {
date = date - 28800;
targetDate = date.toString().length === 10 ? new Date(date * 1000) : new Date(date)
} else {
targetDate = new Date(date)

View File

@@ -9,7 +9,7 @@
<Acheak @click="ChangeChat('2')" :on-value="type" on-cheak="2">帮派</Acheak>.
<Acheak @click="ChangeChat('3')" :on-value="type" on-cheak="3">全区</Acheak>.
<Acheak @click="ChangeChat('4')" :on-value="type" on-cheak="4">全服</Acheak>.
<Acheak @click="ChangeChat('5')" :on-value="type" on-cheak="5">系统</Acheak>
<Acheak @click="ChangeChat('5')" :on-value="type" on-cheak="5">系统</Acheak>
</div>
<div class="content">
<GameChat :data="data" :show-time="1"></GameChat>

View File

@@ -1 +1,129 @@
<template></template>
<template>
<div class="content">
<Acheak @click="ChangeBag('0')" :on-value="type" on-cheak="0">好友</Acheak>|<Acheak @click="ChangeBag('1')"
:on-value="type" on-cheak="1">密友</Acheak>|<Acheak @click="ChangeBag('2')" :on-value="type" on-cheak="2">
师徒</Acheak>|<Acheak @click="ChangeBag('3')" :on-value="type" on-cheak="3">仇人</Acheak>
</div>
<div class="content">
在线/所有({{ online }}/{{ total }})<Abutton @click="Refresh">刷新</Abutton>
</div>
<div class="content" v-if="type == '0' || type == '1'">
<div class="item" v-for="(item, index) in data" :key="index">
{{ PageExtend.GetPageIndex(currentPage, 10, index + 1) }}.
{{ item.isOnline == 1 ? "[在线]" : "[离线]" }}
<GameUser :data="item.user" :show-icon="1"></GameUser>
<span v-if="type == '0'">
({{ item.user.lev }},{{ item.cityName }}{{ item.mapName }})
<Abutton @click="FriendHandle(item.user.userNo)">[×]</Abutton>
</span>
<span v-else>
(亲密度:{{ item.near }})
</span>
</div>
<span v-if="data.length == 0">
{{ type == '0' ? "暂无好友." : "暂无密友." }}
</span>
</div>
<div class="content" v-if="type == '2'">
<span v-if="data.length == 0">暂无师徒.</span>
</div>
<div class="content" v-if="type == '3'">
<span v-if="data.length == 0">暂无仇人.</span>
</div>
<div class="content">
<Pagination :currentPage="currentPage" :limit="10" :total="total" @pageChange="handlePageChange" />
</div>
<div class="clear"></div>
<div class="content">
<Abar href="/friend/search">添加好友</Abar>
</div>
</template>
<script setup lang="ts">
interface friendStorage {
type: string
page: number
}
definePageMeta({
layout: layout.default,
middleware: 'page-loading'
})
const currentPage = ref<number>(1);
const total = ref<number>(0);
const data = ref<Array<any>>([]);
const type = ref('0');
const online = ref(0);
onMounted(async () => {
try {
let localData = LocalStorageExtend.Get<friendStorage>("FriendCache");
if (localData != null) {
type.value = localData.type;
currentPage.value = localData.page;
}
await BindData();
}
finally {
PageLoading.Close();
}
})
const BindData = async (): Promise<void> => {
let result = await RelationService.GetRelation(Number(type.value), currentPage.value);
if (result.code == 0) {
data.value = result.data.data;
total.value = result.data.total;
online.value = result.data.online;
console.log(result);
//存储请求参数
let addLocalData: friendStorage = { type: type.value, page: currentPage.value };
LocalStorageExtend.Set("FriendCache", addLocalData);
}
else {
MessageExtend.ShowDialog("提示", result.msg);
}
};
/**切换背包 */
const ChangeBag = async (_type: string): Promise<void> => {
type.value = _type;
await BindData();
}
/**刷新 */
const Refresh = async (): Promise<void> => {
MessageExtend.LoadingToast("刷新中...");
currentPage.value = 1;
await BindData();
MessageExtend.LoadingClose();
PageExtend.ScrollToTop();
}
/**翻页 */
const handlePageChange = async (page: number): Promise<void> => {
currentPage.value = page;
await BindData();
};
const FriendHandle = async (no:string): Promise<void> => {
MessageExtend.ShowConfirmDialogAsyc("好友操作", `您确定要删除好友吗?`, async () => {
let result = await RelationService.FriendHandle(no);
if (result.code == 0) {
await BindData();
MessageExtend.Notify(result.msg, "success");
}
else {
MessageExtend.Notify(result.msg, "danger");
}
return true;
});
}
</script>

View File

@@ -0,0 +1,50 @@
<template>
<div class="content">
查找好友
</div>
<div class="content">
<div class="common">
<div class="input">
玩家ID:<input name="no" type="number" placeholder="输入玩家ID" maxlength="12" class="ipt" v-model="no" />
</div>
<div class="input">
<input type="button"" class=" btn btn-danger" value="查找玩家" @click="search" />
</div>
</div>
</div>
<div class="clear"></div>
</template>
<script setup lang="ts">
definePageMeta({
layout: layout.default,
middleware: middleware.loading
})
const no = ref('');
const search = async (): Promise<void> => {
if (no.value == null || no.value == '') {
MessageExtend.ShowToast("玩家ID不能为空!", "default");
return;
}
MessageExtend.LoadingToast("查找中...");
let result = await UserService.GetUserBaseInfo(no.value);
MessageExtend.LoadingClose();
if (result.code == 0) {
PageExtend.Redirect("/user/user?no=" + result.data.userNo);
}
else {
MessageExtend.ShowDialog("查找玩家", result.msg);
}
}
onMounted(async () => {
try {
}
finally {
PageLoading.Close();
}
})
</script>

View File

@@ -3,12 +3,18 @@
游戏消息
</div>
<div class="module-title">
<Acheak @click="Change('0')" :on-value="type" on-cheak="0">未读</Acheak>|
<Acheak @click="Change('1')" :on-value="type" on-cheak="1">已读</Acheak>|
<Acheak @click="Change('2')" :on-value="type" on-cheak="2">通知</Acheak>|
<Acheak @click="Change('0')" :on-value="type" on-cheak="0">未读</Acheak>
<span v-if="(countInfo[0] ?? 0) > 0">({{ countInfo[0] }})</span>
|
<Acheak @click="Change('1')" :on-value="type" on-cheak="1">已读</Acheak>
|
<Acheak @click="Change('2')" :on-value="type" on-cheak="2">通知</Acheak>
<span v-if="(countInfo[1] ?? 0) > 0">({{ countInfo[1] }})</span>
|
<Acheak @click="Change('3')" :on-value="type" on-cheak="3">邮件</Acheak>
<span v-if="(countInfo[2] ?? 0) > 0">({{ countInfo[2] }})</span>
</div>
<div class="module-content">
<div class="module-content" v-if="type == '0' || type == '1'">
<div class="item border-btm" v-for="(item, index) in data" :key="index">
{{ PageExtend.GetPageIndex(currentPage, 10, index + 1) }}.
<Abar :href='"/message/read?id=" + item.user.userNo'>
@@ -17,6 +23,42 @@
</div>
<span v-if="data.length == 0">暂无消息.</span>
</div>
<div class="module-content" v-if="type == '2'">
<div class="item border-btm" v-for="(item, index) in data" :key="index">
<div>
{{ PageExtend.GetPageIndex(currentPage, 10, index + 1) }}.
<strong style="font-size: 16px;">{{ item.name }}</strong>
<span v-if="item.state == 0" style="color: red;font-size: 16px;">(未处理)</span>
</div>
<div style="font-size: 14px;">
{{ TimeExtend.Format(item.addTime, "yyyy-MM-dd HH:mm:ss") }}
</div>
<div v-html="item.sign" style="font-size: 15px;" @click="HtmlEvent"></div>
<div v-if="item.state == 0">
<span v-for="(btn, btn_num) in item.btns" :key="btn_num">
<Abutton @click="EventHandle(item.eventId, btn.status)" style="font-size: 16px;">{{ btn.name }}
</Abutton>
</span>
</div>
<div v-else>
<span style="font-size: 15px; ">{{
EventTips(item.btns, item.state) }}</span>
</div>
</div>
<span v-if="data.length == 0">暂无通知.</span>
</div>
<div class="module-content" v-if="type == '3'">
<div class="item border-btm" v-for="(item, index) in data" :key="index">
{{ PageExtend.GetPageIndex(currentPage, 10, index + 1) }}.
<Abar :href='"/message/mail?id=" + item.mailId'>
{{ item.name }}</Abar>
<span v-if="item.isRead == 0" style="color: red;font-size: 16px;">(未读)</span>
<span v-else-if="item.isGet == 0" style="color: red;font-size: 16px;">(未领取)</span>
</div>
<span v-if="data.length == 0">暂无邮件.</span>
</div>
<Pagination :currentPage="currentPage" :limit="10" :total="total" @pageChange="handlePageChange" />
</template>
<script setup lang="ts">
@@ -29,6 +71,7 @@ const type = ref('0');
const currentPage = ref<number>(1);
const total = ref<number>(0);
const data = ref<Array<any>>([]);
const countInfo = ref<number[]>([]);
onMounted(async () => {
try {
let local_type = LocalStorageExtend.Get<string>("MsgType");
@@ -50,7 +93,7 @@ const BindData = async (): Promise<void> => {
if (result.code == 0) {
data.value = result.data.data;
total.value = result.data.total;
console.log(result);
countInfo.value = result.data.msgCount;
}
else {
MessageExtend.ShowDialog("提示", result.msg);
@@ -59,6 +102,7 @@ const BindData = async (): Promise<void> => {
const Change = async (_type: string): Promise<void> => {
currentPage.value = 1;
data.value = [];
type.value = _type;
LocalStorageExtend.Set("MsgType", type.value);
await BindData();
@@ -83,5 +127,26 @@ const delTlak = async (no: number): Promise<void> => {
}
}
/**消息时间处理 */
const EventHandle = async (eventId: string, state: number): Promise<void> => {
MessageExtend.ShowConfirmDialogAsyc("通知消息处理", "您确定要进行该操作吗?", async () => {
let result = await MessageService.EventHandle(eventId, state);
if (result.code == 0) {
MessageExtend.Notify(result.msg, "success");
await BindData();
}
else {
MessageExtend.Notify(result.msg, "danger");
}
return true;
});
}
const EventTips = (btns: Array<any>, state: number): string => {
var data = btns.find(it => it.status == state);
return data.tips;
}
</script>

View File

@@ -0,0 +1,77 @@
<template>
<div class="crumb-nav-large">
<Abar href="/message/">我的邮件</Abar>&gt;邮件信息
</div>
<div class="module-title">
{{ data.name }}
</div>
<div class="module-content">
<div class=" spacing-3">
<span class="data_detail">
{{ data.sign }}
</span>
</div>
<div class=" spacing-3" v-if="award.length > 0">
---附件信息---<br />
<div class="common" v-html="GameTool.GetPropHtml(award, 1, 1)">
</div>
<div class="common" v-if="data.isGet == 0">
<Abutton @click="GetAward">[领取附件]</Abutton>
</div>
<div class="common" style="color:red;font-size:14px;font-weight:bold" v-if="data.isGet == 1">
*附件已领取!
</div>
</div>
<div class=" spacing-3">
发件人:海精灵<br />
发件时间:<small>[{{ TimeExtend.Format(data.addTime) }}]</small><br />
有效时间:<small>[{{ TimeExtend.Format(data.endTime) }}]</small><br />
</div>
</div>
</template>
<script setup lang="ts">
definePageMeta({
layout: layout.default,
middleware: 'page-loading'
})
const data = ref<any>({});
const award = ref<Array<any>>([]);
onMounted(async () => {
try {
await BindData();
}
finally {
PageLoading.Close();
}
})
const BindData = async (): Promise<void> => {
let no = PageExtend.QueryString("id");
let result = await MessageService.GetMailInfo(no);
if (result.code == 0) {
data.value = result.data;
award.value = result.data.award;
}
else {
MessageExtend.ShowDialogEvent("提示", result.msg, () => {
return PageExtend.Redirect("/message");
}, "确认");
}
};
const GetAward = async (): Promise<void> => {
MessageExtend.LoadingToast("领取中...");
let no = PageExtend.QueryString("id");
let result = await MessageService.GetAward(no);
MessageExtend.LoadingClose();
if (result.code == 0) {
await BindData();
MessageExtend.Notify("领取成功!", "success");
}
else {
MessageExtend.ShowDialog("提示", result.msg);
}
}
</script>

View File

@@ -68,8 +68,7 @@ const BindData = async (): Promise<void> => {
if (result.code == 0) {
data.value = result.data.data;
user.value = result.data.user;
logs.value = result.data.logs;
console.log(result);
logs.value = result.data.logs;
}
else {
MessageExtend.ShowDialogEvent("提示", result.msg, () => {

View File

@@ -2,7 +2,7 @@
<div class="content">
<Abar :href='"/message/read?id=" + userData.userNo'>私聊</Abar>. <Abar>送礼物</Abar>. <Abar>逗一下</Abar><br />
<Abar>拜师</Abar>. <Abar>山寨</Abar>. <Abar>送道具</Abar><br>
<Abar>加好友</Abar>. <Abar>加仇人</Abar>
<Abutton @click="FriendHandle">{{ isFriend ? "删除好友" : "加好友" }}</Abutton>. <Abar>加仇人</Abar>
</div>
<div class="content"></div>
<div class="content">
@@ -51,6 +51,7 @@ const attrData = ref<any>({});
const accData = ref<any>({});
const online = ref(0);
const onMap = ref('');
const isFriend = ref(false);
onMounted(async () => {
try {
@@ -72,14 +73,15 @@ const BindData = async (): Promise<void> => {
accData.value = result.data.acc;
online.value = result.data.isOnline;
onMap.value = result.data.onMapName;
isFriend.value = result.data.isFriend;
console.log(result);
}
else if (result.code == 101) {
return PageExtend.Redirect("/user");
return PageExtend.RedirectTo("/user");
}
else if (result.code == 102) {
MessageExtend.ShowDialogEvent("提示", "玩家不存在!", () => {
return PageExtend.Redirect("/user");
return PageExtend.RedirectTo("/user");
}, "确认");
}
else {
@@ -87,4 +89,20 @@ const BindData = async (): Promise<void> => {
}
};
const FriendHandle = async (): Promise<void> => {
MessageExtend.ShowConfirmDialogAsyc("好友操作", `您确定要${isFriend.value ? "删除" : "添加"}好友吗?`, async () => {
let no = PageExtend.QueryString("no");
let result = await RelationService.FriendHandle(no);
if (result.code == 0) {
await BindData();
MessageExtend.Notify(result.msg, "success");
}
else {
MessageExtend.Notify(result.msg, "danger");
}
return true;
});
}
</script>

View File

@@ -40,4 +40,28 @@ export class MessageService {
static async DeleteMsg(no: number) {
return await ApiService.Request("get", "/Message/DeleteMsg", { no });
}
/**
* 获取邮件详情
* GET /Message/GetMailInfo
*/
static async GetMailInfo(no: string) {
return await ApiService.Request("get", "/Message/GetMailInfo", { no });
}
/**
* 领取附件
* GET /Message/GetAward
*/
static async GetAward(no: string) {
return await ApiService.Request("get", "/Message/GetAward", { no });
}
/**
* 处理事件消息
* GET /Message/EventHandle
*/
static async EventHandle(eventId: string, state: number) {
return await ApiService.Request("get", "/Message/EventHandle", { eventId, state });
}
}

View File

@@ -0,0 +1,17 @@
export class RelationService {
/**
* 关系列表数据
* GET /User/Relation/GetRelation
*/
static async GetRelation(type: number, page: number) {
return await ApiService.Request("get", "/User/Relation/GetRelation", { type, page });
}
/**
* FriendHandle
* GET /User/Relation/FriendHandle
*/
static async FriendHandle(no: string) {
return await ApiService.Request("get", "/User/Relation/FriendHandle", { no });
}
}

View File

@@ -7,6 +7,14 @@ export class UserService {
return await ApiService.Request("get", "/User/User/GetUserInfo");
}
/**
* 获取基础资料信息
* GET /User/User/GetUserBaseInfo
*/
static async GetUserBaseInfo(no: string) {
return await ApiService.Request("get", "/User/User/GetUserBaseInfo", { no });
}
/**
* 获取用户资料
* GET /User/User/GetHomeInfo

View File

@@ -68,7 +68,7 @@ export class GameTool {
result = '金贝';
break;
case 'copper':
return this.FormatCopper(num);
return this.FormatCopper(num);
break;
case 'teach':
result = '师德';
@@ -80,4 +80,35 @@ export class GameTool {
return `${num}${result}`;
}
/**物品连接处理 */
public static GetPropHtml(data: Array<any>, count: number, type: number): string {
let result = ''
data.forEach(element => {
let num = Number(element.count) * count;
if (type == 0) {
result += `${element.name}+${num}`
}
else {
result += `<div class='n-item'>▸${this.GetPropUrl(element.code, element.name, element.parameter)}+${num}</div>`;
}
});
result = StringExtend.trimEnd(result, ',');
return result;
}
public static GetPropUrl(code: string, name: string, par: string): string {
let result = name;
switch (code) {
case "Equ":
result = `<a href='/prop/equ?id=${par}'>${name}</a>`;
break;
case "Goods":
result = `<a href='/prop/goods?id=${par}'>${name}</a>`;
break;
}
return result;
}
}