导入 AKSRT 主题开发源码

This commit is contained in:
Claude Code committed 2026-07-03 22:50:34 +08:00
1 parent 9681dd3d48
commit 1268a55dd0
595 files changed
+127705

No files matched your search

@@ -0,0 +1,258 @@
<template>
<div class="aksrt-page-container">
<PageHeader title="微信模板消息" desc="配置微信公众号模板消息推送。" />
<!-- 状态卡片 -->
<div class="aksrt-wechat__status">
<div class="aksrt-wechat__status-card">
<div class="aksrt-wechat__status-icon" :class="status.configured ? 'aksrt-wechat__status-icon--ok' : 'aksrt-wechat__status-icon--warn'">
<i :class="status.configured ? 'fas fa-check' : 'fas fa-exclamation'"></i>
</div>
<div class="aksrt-wechat__status-info">
<div class="aksrt-wechat__status-label">配置状态</div>
<div class="aksrt-wechat__status-value">{{ status.configured ? '已配置' : '未配置' }}</div>
</div>
</div>
<div class="aksrt-wechat__status-card">
<div class="aksrt-wechat__status-icon" :class="status.has_token ? 'aksrt-wechat__status-icon--ok' : 'aksrt-wechat__status-icon--warn'">
<i :class="status.has_token ? 'fas fa-key' : 'fas fa-key'"></i>
</div>
<div class="aksrt-wechat__status-info">
<div class="aksrt-wechat__status-label">Access Token</div>
<div class="aksrt-wechat__status-value">{{ status.has_token ? '已获取' : '未获取' }}</div>
</div>
</div>
<div class="aksrt-wechat__status-card">
<div class="aksrt-wechat__status-icon" :class="status.has_template ? 'aksrt-wechat__status-icon--ok' : 'aksrt-wechat__status-icon--warn'">
<i :class="status.has_template ? 'fas fa-file-alt' : 'fas fa-file-alt'"></i>
</div>
<div class="aksrt-wechat__status-info">
<div class="aksrt-wechat__status-label">模板 ID</div>
<div class="aksrt-wechat__status-value">{{ status.has_template ? '已配置' : '未配置' }}</div>
</div>
</div>
<div class="aksrt-wechat__status-card">
<div class="aksrt-wechat__status-icon aksrt-wechat__status-icon--info">
<i class="fas fa-users"></i>
</div>
<div class="aksrt-wechat__status-info">
<div class="aksrt-wechat__status-label">绑定用户</div>
<div class="aksrt-wechat__status-value">{{ status.bound_users || 0 }} 人</div>
</div>
</div>
</div>
<!-- 配置表单 -->
<div class="aksrt-wechat__form-card">
<h3>基本配置</h3>
<div class="aksrt-form-group">
<label>
<input type="checkbox" v-model="form.enabled"> 启用微信模板消息
</label>
</div>
<div class="aksrt-form-group">
<label>AppID</label>
<input v-model="form.app_id" type="text" class="aksrt-input" placeholder="微信公众号 AppID">
</div>
<div class="aksrt-form-group">
<label>AppSecret</label>
<input v-model="form.app_secret" type="password" class="aksrt-input" placeholder="微信公众号 AppSecret">
<p class="aksrt-form-hint">保存后不会回显完整密钥</p>
</div>
<div class="aksrt-form-group">
<label>模板 ID</label>
<input v-model="form.template_id" type="text" class="aksrt-input" placeholder="微信模板消息模板 ID">
</div>
<div class="aksrt-form-actions">
<button class="aksrt-button aksrt-button--primary" :disabled="saving" @click="saveSettings">
{{ saving ? '保存中...' : '保存设置' }}
</button>
</div>
</div>
<!-- 通知类型 -->
<div class="aksrt-wechat__form-card">
<h3>支持的通知类型</h3>
<p class="aksrt-form-hint">以下事件类型可触发微信模板消息推送(需用户绑定微信且开启对应订阅):</p>
<table class="aksrt-table aksrt-table--sm">
<thead>
<tr>
<th>事件类型</th>
<th>说明</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<tr v-for="evt in eventTypes" :key="evt.key">
<td><code>{{ evt.key }}</code></td>
<td>{{ evt.desc }}</td>
<td>
<span class="aksrt-badge" :class="evt.ready ? 'aksrt-badge--success' : 'aksrt-badge--warning'">
{{ evt.ready ? '可用' : '待接入' }}
</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
import { ref, reactive, computed, onMounted } from 'vue';
import PageHeader from '@/components/PageHeader.vue';
import api from '@/api';
export default {
name: 'UsersWechatTemplate',
components: { PageHeader },
setup() {
const status = ref({
enabled: false,
configured: false,
has_token: false,
has_template: false,
bound_users: 0,
});
const form = reactive({
enabled: false,
app_id: '',
app_secret: '',
template_id: '',
});
const saving = ref(false);
// Event type definitions — readiness driven by backend allowed_types
const eventTypeDefs = [
{ key: 'comment_reply', desc: '评论回复通知' },
{ key: 'system_notice', desc: '系统公告通知' },
{ key: 'order_paid', desc: '订单支付通知' },
{ key: 'credits_change', desc: '积分变动通知' },
{ key: 'forum_reply', desc: '论坛回复通知' },
];
const allowedTypes = ref([]);
const eventTypes = computed(() =>
eventTypeDefs.map(et => ({
...et,
ready: allowedTypes.value.length === 0 || allowedTypes.value.includes(et.key),
}))
);
async function loadStatus() {
try {
const json = await api.request('/wechat/status');
if (json.success) {
status.value = json.data;
form.enabled = json.data.enabled || false;
form.app_id = json.data.appid || '';
form.app_secret = json.data.app_secret === '***' ? '' : '';
form.template_id = json.data.template_id || '';
// Use backend allowed_types for readiness (empty = all allowed)
allowedTypes.value = json.data.allowed_types || [];
}
} catch (e) {
console.error('Load WeChat status failed:', e);
}
}
async function saveSettings() {
saving.value = true;
try {
const payload = { ...form };
// 如果密码为空且状态显示已配置,发送掩码保留原值
if (!payload.app_secret && status.value.configured) {
payload.app_secret = '***';
}
const json = await api.request('/wechat/settings', {
method: 'POST',
data: payload,
});
if (json.success) {
alert('设置已保存');
loadStatus();
} else {
alert(json.message || '保存失败');
}
} catch (e) {
console.error('Save failed:', e);
alert('保存失败: ' + (e.message || '未知错误'));
} finally {
saving.value = false;
}
}
onMounted(() => loadStatus());
return { status, form, saving, eventTypes, saveSettings };
},
};
</script>
<style scoped>
.aksrt-wechat__status {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
margin-bottom: 24px;
}
.aksrt-wechat__status-card {
display: flex;
align-items: center;
gap: 12px;
padding: 16px;
background: #fff;
border-radius: 8px;
border: 1px solid #e8e8e8;
}
.aksrt-wechat__status-icon {
width: 40px;
height: 40px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
}
.aksrt-wechat__status-icon--ok {
background: #d4edda;
color: #155724;
}
.aksrt-wechat__status-icon--warn {
background: #fff3cd;
color: #856404;
}
.aksrt-wechat__status-icon--info {
background: #d1ecf1;
color: #0c5460;
}
.aksrt-wechat__status-value {
font-size: 18px;
font-weight: 600;
color: #1a1a2e;
}
.aksrt-wechat__status-label {
font-size: 12px;
color: #888;
}
.aksrt-wechat__form-card {
background: #fff;
border: 1px solid #e8e8e8;
border-radius: 8px;
padding: 24px;
margin-bottom: 16px;
}
.aksrt-wechat__form-card h3 {
margin: 0 0 16px;
font-size: 16px;
font-weight: 600;
}
.aksrt-form-hint {
font-size: 12px;
color: #888;
margin-top: 4px;
}
</style>