(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_OPTION_STATES = ['ACTIVE', 'DISABLED', 'UNKNOWN']; 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, allowedFeedbackTypes) { var source = body || {}; var allowedTypes = Array.isArray(allowedFeedbackTypes) ? allowedFeedbackTypes : []; if (!optionalText(source.feedbackContent)) return '请填写反馈内容'; if (source.feedbackType && allowedTypes.length && allowedTypes.indexOf(source.feedbackType) < 0) { return '反馈类型无效'; } return ''; } function normalizeFeedbackTypeOptions(data) { if (!Array.isArray(data)) return []; return data.reduce(function (options, item) { var source = item || {}; var value = optionalText(source.value); var label = optionalText(source.label); if (value && label && source.enabled === true) options.push({ value: value, label: label }); return options; }, []); } function normalizeFeedback(item) { var source = item || {}; var feedbackId = normalizeId(source.feedbackId); var feedbackType = optionalText(source.feedbackType); var feedbackTypeLabel = optionalText(source.feedbackTypeLabel) || feedbackType; var feedbackTypeOptionState = optionalText(source.feedbackTypeOptionState); 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 || !feedbackType || !feedbackTypeLabel || FEEDBACK_OPTION_STATES.indexOf(feedbackTypeOptionState) < 0 || !Object.prototype.hasOwnProperty.call(HANDLE_STATUS, handleStatus) || ['0', '1'].indexOf(status) < 0) { return null; } return { feedbackId: feedbackId, feedbackType: feedbackType, feedbackTypeLabel: feedbackTypeLabel, feedbackTypeOptionState: feedbackTypeOptionState, 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(item.feedbackTypeLabel) + '

' + 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.feedbackTypeLabel) + '

问题说明

' + 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 isForbidden(error) { return Number(error && (error.status || error.code)) === 403; } function getFormValues(form) { var values = {}; Array.prototype.forEach.call(form.querySelectorAll('[name]'), function (field) { values[field.name] = field.value; }); return values; } function setApiState(target, type, message) { if (!target) return; if (root.ProfileUI && root.ProfileUI.setApiState && type) { root.ProfileUI.setApiState(target, type, message); return; } target.textContent = message || ''; } function setStatus(type, message) { var status = root.document && root.document.querySelector('[data-feedback-status]'); setApiState(status, type, message); } function setFeedbackList(list, items, detailPage) { if (!list) return; if (!items.length) { setApiState(list, 'empty', '当前没有反馈记录。'); return; } list.innerHTML = renderFeedbackList(items, { detailPage: detailPage || 'ticket-detail.html' }); } function setPendingButton(button, pending, label) { if (!button) return; if (!button.dataset.defaultLabel) button.dataset.defaultLabel = button.textContent; button.disabled = pending; button.textContent = pending ? label : button.dataset.defaultLabel; } async function loadFeedbackTypeOptions(api, select) { var options = normalizeFeedbackTypeOptions(await api.businessDictionary('gen_feedback_type')); if (!options.length) throw new Error('反馈类型选项响应无效'); if (select) { select.innerHTML = '' + options.map(function (item) { return ''; }).join(''); } return options; } 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 feedbackTypeSelect = form && form.querySelector('[data-feedback-type-options]'); var allowedFeedbackTypes = []; var writePending = false; if (!form) return; if (shouldRedirectToLogin(api)) { redirectToLogin(api); return; } try { allowedFeedbackTypes = (await loadFeedbackTypeOptions(api, feedbackTypeSelect)).map(function (item) { return item.value; }); } catch (error) { if (feedbackTypeSelect) feedbackTypeSelect.innerHTML = ''; } async function loadList() { var items; if (!list) return []; setApiState(list, 'loading', '正在读取反馈记录…'); setStatus('loading', '正在读取反馈记录…'); try { items = await readMyFeedback(api); setFeedbackList(list, items, 'ticket-detail.html'); setStatus('', ''); return items; } catch (error) { if (shouldRedirectToLogin(api, error)) { redirectToLogin(api); return []; } setApiState(list, isForbidden(error) ? 'forbidden' : 'error', isForbidden(error) ? '暂无权限查看反馈记录。' : '读取反馈记录失败,请稍后重试。'); setStatus(isForbidden(error) ? 'forbidden' : 'error', isForbidden(error) ? '暂无权限查看反馈记录。' : (error.message || '读取反馈记录失败,请稍后重试。')); return []; } } if (refresh) refresh.addEventListener('click', async function () { setPendingButton(refresh, true, '正在刷新…'); try { await loadList(); } finally { setPendingButton(refresh, false, '正在刷新…'); } }); 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, allowedFeedbackTypes); if (validation) { setStatus('error', validation); return; } writePending = true; setPendingButton(button, true, '正在提交…'); setStatus('loading', '正在提交反馈…'); 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; } setFeedbackList(list, refreshed, 'ticket-detail.html'); form.reset(); setStatus('', '反馈已提交'); } catch (error) { if (shouldRedirectToLogin(api, error)) { redirectToLogin(api); return; } setStatus(isForbidden(error) ? 'forbidden' : 'error', isForbidden(error) ? '暂无权限提交反馈。' : (error.message || '提交反馈失败,请稍后重试。')); } finally { writePending = false; setPendingButton(button, 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 { setApiState(list, 'loading', '正在读取反馈记录…'); setStatus('loading', '正在读取反馈记录…'); setFeedbackList(list, await readMyFeedback(api), 'ticket-detail.html'); setStatus('', ''); } catch (error) { if (shouldRedirectToLogin(api, error)) { redirectToLogin(api); return; } setApiState(list, isForbidden(error) ? 'forbidden' : 'error', isForbidden(error) ? '暂无权限查看反馈记录。' : '读取反馈记录失败,请稍后重试。'); setStatus(isForbidden(error) ? 'forbidden' : 'error', isForbidden(error) ? '暂无权限查看反馈记录。' : (error.message || '读取反馈记录失败,请稍后重试。')); } } if (refresh) refresh.addEventListener('click', async function () { setPendingButton(refresh, true, '正在刷新…'); try { await loadList(); } finally { setPendingButton(refresh, false, '正在刷新…'); } }); 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) { setApiState(detail, 'empty', '反馈记录不存在或无权查看。'); return; } if (shouldRedirectToLogin(api)) { redirectToLogin(api); return; } try { setApiState(detail, 'loading', '正在读取反馈详情…'); setStatus('loading', '正在读取反馈详情…'); item = findFeedbackById(await api.myFeedback(), feedbackId); if (item) detail.innerHTML = renderFeedbackDetail(item); else setApiState(detail, 'empty', '反馈记录不存在或无权查看。'); setStatus('', item ? '' : '反馈记录不存在或无权查看。'); } catch (error) { if (shouldRedirectToLogin(api, error)) { redirectToLogin(api); return; } setApiState(detail, isForbidden(error) ? 'forbidden' : 'error', isForbidden(error) ? '暂无权限查看该反馈详情。' : '反馈详情读取失败,请稍后重试。'); setStatus(isForbidden(error) ? 'forbidden' : 'error', isForbidden(error) ? '暂无权限查看该反馈详情。' : (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, normalizeFeedbackTypeOptions: normalizeFeedbackTypeOptions, normalizeFeedback: normalizeFeedback, normalizeFeedbackList: normalizeFeedbackList, findFeedbackById: findFeedbackById, buildFeedbackDetailUrl: buildFeedbackDetailUrl, renderFeedbackList: renderFeedbackList, renderFeedbackDetail: renderFeedbackDetail, isForbidden: isForbidden, initFeedbackFormPage: initFeedbackFormPage, initFeedbackListPage: initFeedbackListPage, initFeedbackDetailPage: initFeedbackDetailPage, init: init }; });