(function (root, factory) { if (typeof module === 'object' && module.exports) { module.exports = factory(root); return; } root.FeedbackPages = factory(root); if (root.document) { root.document.addEventListener('DOMContentLoaded', function () { root.FeedbackPages.init(); }); } })(typeof globalThis !== 'undefined' ? globalThis : window, function (root) { 'use strict'; var FEEDBACK_TYPES = { advice: '意见建议', bug: '问题反馈', complaint: '投诉反馈', other: '其他反馈' }; var HANDLE_STATUS = { '0': '待处理', '1': '处理中', '2': '已处理', '3': '已关闭' }; function escapeHtml(value) { return String(value === undefined || value === null ? '' : value) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function normalizeId(value) { var text; if (typeof value === 'number' && !Number.isSafeInteger(value)) return ''; if (value === undefined || value === null) return ''; text = String(value).trim(); return /^[1-9][0-9]*$/.test(text) ? text : ''; } function optionalText(value) { if (value === undefined || value === null) return ''; return String(value).trim(); } function getFeedbackId(search) { var params = new URLSearchParams(String(search === undefined && root.location ? root.location.search : search || '').replace(/^\?/, '')); return normalizeId(params.get('feedbackId')); } function buildFeedbackBody(values) { var source = values || {}; var body = {}; var feedbackType = optionalText(source.feedbackType); var feedbackContent = optionalText(source.feedbackContent); var contactInfo = optionalText(source.contactInfo); if (feedbackType) body.feedbackType = feedbackType; if (feedbackContent) body.feedbackContent = feedbackContent; if (contactInfo) body.contactInfo = contactInfo; return body; } function validateFeedbackBody(body) { var source = body || {}; if (!optionalText(source.feedbackContent)) return '请填写反馈内容'; if (source.feedbackType && !Object.prototype.hasOwnProperty.call(FEEDBACK_TYPES, source.feedbackType)) { return '反馈类型无效'; } return ''; } function normalizeFeedback(item) { var source = item || {}; var feedbackId = normalizeId(source.feedbackId); var feedbackType = optionalText(source.feedbackType); var feedbackContent = optionalText(source.feedbackContent); var handleStatus = String(source.handleStatus === undefined || source.handleStatus === null ? '' : source.handleStatus); var status = String(source.status === undefined || source.status === null ? '' : source.status); if (!feedbackId || !feedbackContent || !Object.prototype.hasOwnProperty.call(FEEDBACK_TYPES, feedbackType) || !Object.prototype.hasOwnProperty.call(HANDLE_STATUS, handleStatus) || ['0', '1'].indexOf(status) < 0) { return null; } return { feedbackId: feedbackId, feedbackType: feedbackType, feedbackContent: feedbackContent, contactInfo: optionalText(source.contactInfo), handleStatus: handleStatus, handleResult: optionalText(source.handleResult), handleTime: optionalText(source.handleTime), status: status, remark: optionalText(source.remark) }; } function normalizeFeedbackList(data) { var items; if (!Array.isArray(data)) return []; items = data.map(normalizeFeedback); return items.some(function (item) { return !item; }) ? [] : items; } function findFeedbackById(data, feedbackId) { var targetId = normalizeId(feedbackId); var items = normalizeFeedbackList(data); var match; if (!targetId) return null; match = items.find(function (item) { return item.feedbackId === targetId; }); return match || null; } function buildFeedbackDetailUrl(feedbackId, detailPage) { var id = normalizeId(feedbackId); var params; if (!id) return ''; params = new URLSearchParams(); params.set('feedbackId', id); return (detailPage || 'ticket-detail.html') + '?' + params.toString(); } function renderFeedbackList(data, options) { var settings = options || {}; var items = normalizeFeedbackList(data); var detailPage = settings.detailPage || 'ticket-detail.html'; if (!items.length) return '
当前没有反馈记录
'; return items.map(function (item) { return '

' + escapeHtml(FEEDBACK_TYPES[item.feedbackType]) + '

' + escapeHtml(item.feedbackContent) + '

' + HANDLE_STATUS[item.handleStatus] + '
'; }).join(''); } function renderFeedbackDetail(item) { var feedback = normalizeFeedback(item); var details; if (!feedback) return '
反馈记录不存在或无权查看
'; details = [ feedback.contactInfo ? '
提交联系方式
' + escapeHtml(feedback.contactInfo) + '
' : '', '
处理状态
' + HANDLE_STATUS[feedback.handleStatus] + '
', feedback.handleResult ? '
处理结果
' + escapeHtml(feedback.handleResult) + '
' : '', feedback.handleTime ? '
处理时间
' + escapeHtml(feedback.handleTime) + '
' : '', feedback.remark ? '
备注
' + escapeHtml(feedback.remark) + '
' : '' ].filter(Boolean).join(''); return '
' + escapeHtml(FEEDBACK_TYPES[feedback.feedbackType]) + '

问题说明

' + escapeHtml(feedback.feedbackContent) + '

' + details + '
'; } function shouldRedirectToLogin(api, error) { var status = error && (error.status || error.code); return !api || !api.getToken || !api.getToken() || Number(status) === 401; } function redirectToLogin(api) { if (api && api.clearToken) api.clearToken(); if (!root.location) return; if (typeof root.location.replace === 'function') root.location.replace('login.html'); else root.location.href = 'login.html'; } function getFormValues(form) { var values = {}; Array.prototype.forEach.call(form.querySelectorAll('[name]'), function (field) { values[field.name] = field.value; }); return values; } function setStatus(message) { var status = root.document && root.document.querySelector('[data-feedback-status]'); if (status) status.textContent = message || ''; } async function readMyFeedback(api) { var data = await api.myFeedback(); var items = normalizeFeedbackList(data); if (!Array.isArray(data) || items.length !== data.length) { throw new Error('反馈列表响应无效'); } return items; } async function initFeedbackFormPage() { var form = root.document && root.document.querySelector('[data-feedback-form]'); var list = root.document && root.document.querySelector('[data-feedback-list]'); var refresh = root.document && root.document.querySelector('[data-feedback-refresh]'); var page = root.document && root.document.querySelector('[data-feedback-page]'); var api = root.GenealogyApi && root.GenealogyApi.defaultClient; var pageMode = page && page.getAttribute('data-feedback-page'); var writePending = false; if (!form) return; if (shouldRedirectToLogin(api)) { redirectToLogin(api); return; } async function loadList() { var items; if (!list) return []; setStatus('正在读取反馈记录…'); try { items = await readMyFeedback(api); list.innerHTML = renderFeedbackList(items, { detailPage: 'ticket-detail.html' }); setStatus(''); return items; } catch (error) { if (shouldRedirectToLogin(api, error)) { redirectToLogin(api); return []; } list.innerHTML = '
读取反馈记录失败
'; setStatus(error.message || '读取反馈记录失败,请稍后重试'); return []; } } if (refresh) refresh.addEventListener('click', loadList); form.addEventListener('submit', async function (event) { var body; var validation; var created; var refreshed; var button = form.querySelector('[data-feedback-submit]'); event.preventDefault(); if (writePending) return; body = buildFeedbackBody(getFormValues(form)); validation = validateFeedbackBody(body); if (validation) { setStatus(validation); return; } writePending = true; if (button) button.disabled = true; setStatus('正在提交反馈…'); try { created = normalizeFeedback(await api.submitFeedback(body)); if (!created) throw new Error('提交响应缺少有效反馈信息'); refreshed = await readMyFeedback(api); if (!refreshed.some(function (item) { return item.feedbackId === created.feedbackId; })) { throw new Error('提交后无法读取同一反馈记录'); } if (pageMode === 'ticket') { if (root.location) root.location.href = buildFeedbackDetailUrl(created.feedbackId); return; } if (list) list.innerHTML = renderFeedbackList(refreshed, { detailPage: 'ticket-detail.html' }); form.reset(); setStatus('反馈已提交'); } catch (error) { if (shouldRedirectToLogin(api, error)) { redirectToLogin(api); return; } setStatus(error.message || '提交反馈失败,请稍后重试'); } finally { writePending = false; if (button) button.disabled = false; } }); await loadList(); } async function initFeedbackListPage() { var page = root.document && root.document.querySelector('[data-feedback-list-page]'); var list = root.document && root.document.querySelector('[data-feedback-list]'); var refresh = root.document && root.document.querySelector('[data-feedback-refresh]'); var api = root.GenealogyApi && root.GenealogyApi.defaultClient; if (!page || !list) return; if (shouldRedirectToLogin(api)) { redirectToLogin(api); return; } async function loadList() { try { setStatus('正在读取反馈记录…'); list.innerHTML = renderFeedbackList(await readMyFeedback(api), { detailPage: 'ticket-detail.html' }); setStatus(''); } catch (error) { if (shouldRedirectToLogin(api, error)) { redirectToLogin(api); return; } list.innerHTML = '
读取反馈记录失败
'; setStatus(error.message || '读取反馈记录失败,请稍后重试'); } } if (refresh) refresh.addEventListener('click', loadList); await loadList(); } async function initFeedbackDetailPage() { var page = root.document && root.document.querySelector('[data-feedback-detail-page]'); var detail = root.document && root.document.querySelector('[data-feedback-detail]'); var api = root.GenealogyApi && root.GenealogyApi.defaultClient; var feedbackId = getFeedbackId(); var item; if (!page || !detail) return; if (!feedbackId) { detail.innerHTML = '
反馈记录不存在或无权查看
'; return; } if (shouldRedirectToLogin(api)) { redirectToLogin(api); return; } try { setStatus('正在读取反馈详情…'); item = findFeedbackById(await api.myFeedback(), feedbackId); detail.innerHTML = renderFeedbackDetail(item); setStatus(item ? '' : '反馈记录不存在或无权查看'); } catch (error) { if (shouldRedirectToLogin(api, error)) { redirectToLogin(api); return; } detail.innerHTML = '
反馈详情读取失败
'; setStatus(error.message || '反馈详情读取失败,请稍后重试'); } } async function init() { if (root.document && root.document.querySelector('[data-feedback-form]')) { await initFeedbackFormPage(); return; } if (root.document && root.document.querySelector('[data-feedback-list-page]')) { await initFeedbackListPage(); return; } if (root.document && root.document.querySelector('[data-feedback-detail-page]')) { await initFeedbackDetailPage(); } } return { getFeedbackId: getFeedbackId, buildFeedbackBody: buildFeedbackBody, validateFeedbackBody: validateFeedbackBody, normalizeFeedback: normalizeFeedback, normalizeFeedbackList: normalizeFeedbackList, findFeedbackById: findFeedbackById, buildFeedbackDetailUrl: buildFeedbackDetailUrl, renderFeedbackList: renderFeedbackList, renderFeedbackDetail: renderFeedbackDetail, initFeedbackFormPage: initFeedbackFormPage, initFeedbackListPage: initFeedbackListPage, initFeedbackDetailPage: initFeedbackDetailPage, init: init }; });