const STORAGE_PATH = `data/.cache/${Plugin.id}_repos.json` /* 触发器 手动触发 */ const onRun = async () => { const component = { template: `
{{ repo.name }}
`, setup() { const { ref, onMounted } = Vue const input = ref('') const loading = ref(false) const repos = ref([]) const comments = ref([]) async function loadRepos() { const content = await Plugins.ReadFile(STORAGE_PATH).catch(() => '') if (content) { try { repos.value = JSON.parse(content) } catch (e) { console.log(`[${Plugin.name}]`, '解析 repos.json 失败: ', e) } } } async function saveRepos() { try { await Plugins.WriteFile(STORAGE_PATH, JSON.stringify(repos.value, null, 2)) } catch (e) { console.log(`[${Plugin.name}]`, '保存 repos.json 失败: ', e) } } async function fetchCommitsForRepo(repo) { // repo 可能是 "owner/repo" 或 "owner/repo@branch" const [fullRepo, branch = ''] = repo.split('@') const [owner, repoName] = fullRepo.split('/') const url = `https://api.github.com/repos/${owner}/${repoName}/commits?per_page=20${branch ? `&sha=${encodeURIComponent(branch)}` : ''}` const { status, body } = await Plugins.HttpGet(url, { Accept: 'application/vnd.github.v3+json', Authorization: Plugin.TOKEN_MODE === 'gui' ? Plugins.getGitHubApiAuthorization() : Plugin.TOKEN_MODE === 'plugin' ? `Bearer ${Plugin.TOKEN}` : '' }) if (status < 200 || status >= 300) { throw new Error(`获取 ${repo} 提交失败,状态码 ${status}`) } return body } async function handleAddRepo() { const repo = input.value.trim() if (!repo) return repos.value.push({ name: repo, hash: '' }) await saveRepos() input.value = '' } async function handleRemoveRepo(index) { repos.value.splice(index, 1) await saveRepos() } async function handleChange(repo) { comments.value = [] loading.value = true try { const res = await fetchCommitsForRepo(repo.name) const lastHashIndex = res.findIndex((v) => v.sha === repo.hash) if (lastHashIndex !== -1) { res.forEach((comment, index) => { if (index >= lastHashIndex) { comment.selected = true } }) } comments.value = res if (res[0]?.sha) { repo.hash = res[0]?.sha await saveRepos() } } catch (e) { Plugins.message.error(e.message || e) } finally { loading.value = false } } onMounted(() => loadRepos()) return { loading, input, repos, comments, handleAddRepo, handleRemoveRepo, handleChange, formatTime(d) { return Plugins.formatRelativeTime(d) }, handleView(c, url) { c.selected = true Plugins.BrowserOpenURL(url) }, getMessage(msg) { return msg.split('\n')[0] } } } } const modal = Plugins.modal( { title: Plugin.name, maskClosable: true, submit: false, cancelText: 'common.close', width: '90', height: '90' }, { default: () => Vue.h(component) } ) modal.open() }