(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
};
});