Merge pull request #11 from 34892002/dev

1.4.7
This commit is contained in:
ggyy
2026-06-30 17:22:12 +08:00
committed by GitHub
12 changed files with 84 additions and 3 deletions

3
.gitignore vendored
View File

@@ -151,3 +151,6 @@ cdk.out
# prisma部署d1的客户端产物
/generated/prisma/
# 本地SQLite数据库
prisma/db.sqlite

View File

@@ -1,5 +1,15 @@
# Change Log
## v1.4.7 (2026-06-30)
### Features
- **site:** 新增页头/页脚自定义代码注入功能,支持在后台添加统计 JS、Meta 标签、客服插件等自定义代码
### Bug Fixes
- **payment:** 修复 TypeScript 类型错误
## v1.4.6 (2026-06-21)
### Features

View File

@@ -71,6 +71,14 @@ const defaultPaymentConfigs: Record<PaymentProvider, PaymentConfigValue> = {
notifyUrl: "/api/payments/stripe/notify",
returnUrl: "/order/{orderNo}?token={token}",
},
FREE_PAY: {
provider: "FREE_PAY",
name: "免费下单",
isEnabled: false,
baseUrl: "",
notifyUrl: "/api/payments/free/notify",
returnUrl: "/order/{orderNo}?token={token}",
},
};
function getPaymentContext() {

View File

@@ -18,6 +18,8 @@ export function upsertSiteSettingRecord(
supportContact?: string | null;
footerText?: string | null;
orderNotice?: string | null;
headCode?: string | null;
footerCode?: string | null;
},
) {
return prisma.siteSetting.upsert({
@@ -33,6 +35,8 @@ export function upsertSiteSettingRecord(
supportContact: input.supportContact ?? null,
footerText: input.footerText ?? null,
orderNotice: input.orderNotice ?? null,
headCode: input.headCode ?? null,
footerCode: input.footerCode ?? null,
},
update: {
siteName: input.siteName,
@@ -44,6 +48,8 @@ export function upsertSiteSettingRecord(
supportContact: input.supportContact ?? null,
footerText: input.footerText ?? null,
orderNotice: input.orderNotice ?? null,
headCode: input.headCode ?? null,
footerCode: input.footerCode ?? null,
},
});
}

View File

@@ -15,6 +15,8 @@ const defaultSiteSetting = {
supportContact: null,
footerText: null,
orderNotice: null,
headCode: null,
footerCode: null,
};
function normalizeSetting(record: Awaited<ReturnType<typeof getSiteSettingRecord>>) {
@@ -32,6 +34,8 @@ function normalizeSetting(record: Awaited<ReturnType<typeof getSiteSettingRecord
supportContact: record.supportContact,
footerText: record.footerText,
orderNotice: record.orderNotice,
headCode: record.headCode,
footerCode: record.footerCode,
};
}
@@ -61,6 +65,8 @@ export async function saveSiteSetting(input: SiteSettingInput) {
supportContact: input.supportContact?.trim() || null,
footerText: input.footerText?.trim() || null,
orderNotice: input.orderNotice?.trim() || null,
headCode: input.headCode ?? null,
footerCode: input.footerCode ?? null,
});
await logAdminOperation(

View File

@@ -8,4 +8,6 @@ export interface SiteSettingInput {
supportContact?: string | null;
footerText?: string | null;
orderNotice?: string | null;
headCode?: string | null;
footerCode?: string | null;
}

View File

@@ -1,6 +1,6 @@
{
"version": "1.4.6",
"scripts": {
"version": "1.4.7",
"scripts": {
"dev": "vike dev",
"build": "bun run db:generate && vike build",
"preview": "vike build && vike preview",

View File

@@ -66,11 +66,13 @@
</details>
</div>
</footer>
<!-- footerCode 通过 onMounted 动态注入 -->
</div>
</template>
<script setup lang="ts">
import { computed } from "vue";
import { computed, onMounted } from "vue";
import AppButton from "../components/AppButton.vue";
import { usePageContext } from "vike-vue/usePageContext";
@@ -89,8 +91,24 @@ const supportContactItems = computed(() => {
});
});
const footerText = computed(() => pageContext.site?.footerText || "");
const headCode = computed(() => pageContext.site?.headCode || "");
const footerCode = computed(() => pageContext.site?.footerCode || "");
const isAdminRoute = computed(() => pageContext.urlPathname?.startsWith("/admin"));
function injectCode(html: string, target: Element) {
const doc = new DOMParser().parseFromString(html, "text/html");
doc.querySelectorAll("script").forEach((old) => {
const s = document.createElement("script");
s.textContent = old.textContent;
target.appendChild(s);
});
}
onMounted(() => {
if (headCode.value) injectCode(headCode.value, document.body);
if (footerCode.value) injectCode(footerCode.value, document.body);
});
</script>
<style>

View File

@@ -66,6 +66,23 @@
<textarea v-model="form.orderNotice" class="textarea textarea-bordered w-full" rows="4"></textarea>
</label>
<div class="divider">自定义代码</div>
<div class="grid gap-4 md:grid-cols-2">
<label class="flex flex-col gap-1.5">
<span class="label-text font-medium">页头代码 (head)</span>
<textarea v-model="form.headCode" class="textarea textarea-bordered w-full font-mono text-sm" rows="6" placeholder="&lt;meta name=&quot;...&quot; content=&quot;...&quot;&gt;
&lt;script&gt;...&lt;/script&gt;"></textarea>
<span class="text-xs text-base-content/50">注入到 &lt;head&gt; 标签内可用于添加统计代码Meta 标签等</span>
</label>
<label class="flex flex-col gap-1.5">
<span class="label-text font-medium">页脚代码 (body)</span>
<textarea v-model="form.footerCode" class="textarea textarea-bordered w-full font-mono text-sm" rows="6" placeholder="&lt;script&gt;...&lt;/script&gt;
&lt;div&gt;...&lt;/div&gt;"></textarea>
<span class="text-xs text-base-content/50">注入到 &lt;/body&gt; JS </span>
</label>
</div>
<div class="flex items-center gap-3">
<AppButton variant="primary" :loading="saving" @click="handleSave">保存设置</AppButton>
<span v-if="errorMessage" class="text-sm text-error">{{ errorMessage }}</span>
@@ -103,6 +120,8 @@ const form = reactive({
supportContact: site.supportContact ?? "",
footerText: site.footerText ?? "",
orderNotice: site.orderNotice ?? "",
headCode: site.headCode ?? "",
footerCode: site.footerCode ?? "",
});
const saving = ref(false);
@@ -128,6 +147,8 @@ async function handleSave() {
form.supportContact = result.supportContact ?? "";
form.footerText = result.footerText ?? "";
form.orderNotice = result.orderNotice ?? "";
form.headCode = result.headCode ?? "";
form.footerCode = result.footerCode ?? "";
saved.value = true;
} catch (error) {
errorMessage.value = normalizeTelefuncError(error, "保存失败");

View File

@@ -11,6 +11,8 @@ export async function onSaveSiteSettings(input: {
supportContact?: string;
footerText?: string;
orderNotice?: string;
headCode?: string;
footerCode?: string;
}) {
assertAdminAccess();
return saveSiteSetting(input);

View File

@@ -0,0 +1,3 @@
-- AlterTable: Add head and footer custom code fields
ALTER TABLE "SiteSetting" ADD COLUMN "headCode" TEXT;
ALTER TABLE "SiteSetting" ADD COLUMN "footerCode" TEXT;

View File

@@ -156,6 +156,8 @@ model SiteSetting {
supportContact String?
footerText String?
orderNotice String?
headCode String?
footerCode String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}