diff --git a/src/components/userScripts/tus-sign.vue b/src/components/userScripts/tus-sign.vue
new file mode 100644
index 00000000..8157440d
--- /dev/null
+++ b/src/components/userScripts/tus-sign.vue
@@ -0,0 +1,404 @@
+
+
+
+
+
+
+ mdi-checkbox-marked-outline
+
+
mdi-checkbox-blank-outline
+
+
![icon]()
+
{{ item.account.gameUid }} {{ item.account.regionName }}
+
+
+
+
+ {{ item.reward.cnt }}
+
+
mdi-check-circle
+
mdi-circle
+
+
+
+
+
+
+
diff --git a/src/pages/User/Scripts.vue b/src/pages/User/Scripts.vue
index 853a2600..8d25717a 100644
--- a/src/pages/User/Scripts.vue
+++ b/src/pages/User/Scripts.vue
@@ -56,8 +56,8 @@
@@ -69,6 +69,7 @@ import showLoading from "@comp/func/loading.js";
import showSnackbar from "@comp/func/snackbar.js";
import TusMission from "@comp/userScripts/tus-mission.vue";
import TusOutput from "@comp/userScripts/tus-output.vue";
+import TusSign from "@comp/userScripts/tus-sign.vue";
import TSUserAccount from "@Sqlite/modules/userAccount.js";
import { storeToRefs } from "pinia";
import { onMounted, ref, shallowRef } from "vue";
diff --git a/src/types/BBS/Sign.d.ts b/src/types/BBS/Sign.d.ts
new file mode 100644
index 00000000..a6457666
--- /dev/null
+++ b/src/types/BBS/Sign.d.ts
@@ -0,0 +1,131 @@
+/**
+ * @file types/BBS/Sign.d.ts
+ * @description 米游社游戏签到模块相关类型声明
+ * @since Beta v0.7.2
+ */
+
+declare namespace TGApp.BBS.Sign {
+ /**
+ * @description 获取签到奖励信息返回
+ * @interface HomeResp
+ * @since Beta v0.7.2
+ * @extends TGApp.BBS.Response.BaseWithData
+ * @property {HomeRes} data - 返回数据
+ * @returns HomeResp
+ */
+ type HomeResp = TGApp.BBS.Response.BaseWithData;
+
+ /**
+ * @description 获取签到奖励信返回数据
+ * @interface HomeRes
+ * @property {number} month - 月份
+ * @property {Array} awards - 签到奖励列表
+ * @property {string} biz - 业务标识
+ * @property {boolean} resign - 是否补签
+ * @property {HomeAwardExtra} short_extra_award - 签到额外奖励
+ * @returns HomeRes
+ */
+ type HomeRes = {
+ month: number;
+ awards: Array;
+ biz: string;
+ resign: boolean;
+ short_extra_award: HomeAwardExtra;
+ };
+
+ /**
+ * @description 签到奖励
+ * @interface HomeAward
+ * @property {string} icon - 奖励图标
+ * @property {string} name - 奖励名称
+ * @property {number} cnt - 奖励数量
+ * @returns HomeAward
+ */
+ type HomeAward = { icon: string; name: string; cnt: number };
+
+ /**
+ * @description 签到额外奖励
+ * @interface HomeAwardExtra
+ * @property {boolean} has_extra_award - 是否有额外奖励
+ * @property {string} start_time - 额外奖励开始时间
+ * @property {string} end_time - 额外奖励结束时间
+ * @property {Array} list - 额外奖励列表
+ * @property {string} start_timestamp - 额外奖励开始时间戳
+ * @property {string} end_timestamp - 额外奖励结束时间戳
+ * @returns HomeAwardExtra
+ */
+ type HomeAwardExtra = {
+ has_extra_award: boolean;
+ start_time: string;
+ end_time: string;
+ list: Array;
+ start_timestamp: string;
+ end_timestamp: string;
+ };
+
+ /**
+ * @description 获取签到信息返回
+ * @interface InfoResp
+ * @since Beta v0.7.2
+ * @extends TGApp.BBS.Response.BaseWithData
+ * @property {InfoRes} data - 返回数据
+ * @returns InfoResp
+ */
+ type InfoResp = TGApp.BBS.Response.BaseWithData;
+
+ /**
+ * @description 获取签到信息返回数据
+ * @interface InfoRes
+ * @since Beta v0.7.2
+ * @property {number} total_sign_day - 总签到天数
+ * @property {string} today - 今日日期
+ * @property {boolean} is_sign - 是否已签到
+ * @property {boolean} is_sub - 是否已补签
+ * @property {string} region - 服务器
+ * @property {number} sign_cnt_missed - 未签到天数
+ * @property {number} short_sign_day - 未知属性
+ * @property {boolean} send_first - 是否首签
+ * @return InfoRes
+ */
+ type InfoRes = {
+ total_sign_day: number;
+ today: string;
+ is_sign: boolean;
+ is_sub: boolean;
+ region: string;
+ sign_cnt_missed: number;
+ short_sign_day: number;
+ send_first: boolean;
+ };
+
+ /**
+ * @description 签到返回
+ * @interface SignResp
+ * @since Beta v0.7.2
+ * @extends TGApp.BBS.Response.BaseWithData
+ * @property {SignRes} data - 返回数据
+ * @returns SignResp
+ */
+ type SignResp = TGApp.BBS.Response.BaseWithData;
+
+ /**
+ * @description 签到返回数据
+ * @interface SignRes
+ * @since Beta v0.7.2
+ * @property {string} challenge - gt-challenge
+ * @property {string} code - 签到状态码
+ * @property {string} gt - gt
+ * @property {boolean} is_risk - 是否有风险
+ * @property {number} risk_code - 风险码
+ * @property {number} success - 是否成功
+ * @return SignRes
+ */
+ type SignRes = {
+ challenge: string;
+ code: string;
+ gt: string;
+ is_risk: boolean;
+ risk_code: number;
+ success: number;
+ };
+}
diff --git a/src/web/request/lunaReq.ts b/src/web/request/lunaReq.ts
new file mode 100644
index 00000000..7e88ed4d
--- /dev/null
+++ b/src/web/request/lunaReq.ts
@@ -0,0 +1,152 @@
+/**
+ * @file web/request/lunaReq.ts
+ * @description 签到模块请求
+ * @since Beta v0.7.2
+ */
+import TGBbs from "@/utils/TGBbs.js";
+import TGHttp from "@/utils/TGHttp.js";
+import { getRequestHeader } from "@/web/utils/getRequestHeader.js";
+
+// takumiEventLunaApiBaseUrl => telaBu
+const telaBu: Readonly = "https://api-takumi.mihoyo.com/event/luna/";
+
+type ReqParam = { host?: string; actId: string };
+
+/**
+ * @description 根据服务器获取actId跟host
+ * @since Beta v0.7.2
+ * @param {string} region - 服务器
+ * @returns {string} actId
+ */
+function getActConf(region: string): ReqParam | false {
+ switch (region) {
+ // 崩坏2
+ case "bh2_cn":
+ return { actId: "e202203291431091" };
+ // 崩坏3
+ case "bh3_cn":
+ return { actId: "e202306201626331" };
+ // 原神
+ case "hk4e_cn":
+ return { actId: "e202311201442471", host: "hk4e" };
+ // 崩坏:星穹铁道
+ case "hkrpg_cn":
+ return { actId: "e202304121516551", host: "hkrpg" };
+ // 未定事件簿
+ case "nxx_cn":
+ return { actId: "e202202251749321" };
+ // 绝区零
+ case "nap_cn":
+ return { actId: "e202406242138391", host: "zzz" };
+ default:
+ return false;
+ }
+}
+
+/**
+ * @description 获取签到奖励列表
+ * @since Beta v0.7.2
+ * @property {TGApp.Sqlite.Account.Game} account - 账号信息
+ * @property {Record} cookie - cookies
+ * @returns {Promise}
+ */
+async function getLunaHome(
+ account: TGApp.Sqlite.Account.Game,
+ cookie: Record,
+): Promise {
+ const conf = getActConf(account.gameBiz);
+ if (conf === false) {
+ return { retcode: 1, message: "未知服务器" };
+ }
+ const url = conf.host ? `${telaBu}${conf.host}/home` : `${telaBu}home`;
+ const params = { lang: "zh-cn", act_id: conf.actId };
+ const header: Record = {
+ "user-agent": TGBbs.ua,
+ referer: "https://act.mihoyo.com",
+ cookie: Object.keys(cookie)
+ .map((key) => `${key}=${cookie[key]}`)
+ .join("; "),
+ };
+ if (conf.host) if (conf.host) header["x-rpc-signgame"] = conf.host;
+ const resp = await TGHttp(url, {
+ method: "GET",
+ query: params,
+ headers: header,
+ });
+ if (resp.retcode !== 0) return resp;
+ return resp.data;
+}
+
+/**
+ * @description 获取签到信息
+ * @since Beta v0.7.2
+ * @property {TGApp.Sqlite.Account.Game} account - 账号信息
+ * @property {Record} cookie - cookies
+ * @returns {Promise}
+ */
+async function getLunaInfo(
+ account: TGApp.Sqlite.Account.Game,
+ cookie: Record,
+): Promise {
+ const conf = getActConf(account.gameBiz);
+ if (conf === false) {
+ return { retcode: 1, message: "未知服务器" };
+ }
+ const url = conf.host ? `${telaBu}${conf.host}/info` : `${telaBu}info`;
+ const params = {
+ lang: "zh-cn",
+ act_id: conf.actId,
+ region: account.region,
+ uid: account.gameUid,
+ };
+ const header: Record = {
+ "user-agent": TGBbs.ua,
+ referer: "https://act.mihoyo.com",
+ cookie: Object.keys(cookie)
+ .map((key) => `${key}=${cookie[key]}`)
+ .join("; "),
+ };
+ if (conf.host) header["x-rpc-signgame"] = conf.host;
+ const resp = await TGHttp(url, {
+ method: "GET",
+ query: params,
+ headers: header,
+ });
+ if (resp.retcode !== 0) return resp;
+ return resp.data;
+}
+
+async function lunaSign(
+ account: TGApp.Sqlite.Account.Game,
+ cookie: Record,
+ challenge?: string,
+): Promise {
+ const conf = getActConf(account.gameBiz);
+ if (conf === false) {
+ return { retcode: 1, message: "未知服务器" };
+ }
+ const url = conf.host ? `${telaBu}${conf.host}/sign` : `${telaBu}sign`;
+ const data = {
+ lang: "zh-cn",
+ act_id: conf.actId,
+ region: account.region,
+ uid: account.gameUid,
+ };
+ const header: Record = {
+ ...getRequestHeader(cookie, "POST", JSON.stringify(data), "X6"),
+ "x-rpc-client_type": "2",
+ };
+ if (conf.host) header["x-rpc-signgame"] = conf.host;
+ if (challenge) header["x-rpc-challenge"] = challenge;
+ const resp = await TGHttp(url, {
+ method: "POST",
+ headers: header,
+ body: JSON.stringify(data),
+ });
+ if (resp.retcode !== 0) return resp;
+ return resp.data;
+}
+
+const lunaReq = { home: getLunaHome, info: getLunaInfo, sign: lunaSign };
+
+export default lunaReq;