264 lines
8.5 KiB
JavaScript
264 lines
8.5 KiB
JavaScript
class VectorizedPanel extends zui.Component
|
|
{
|
|
static NAME = 'VectorizedPanel';
|
|
|
|
get actualStatus()
|
|
{
|
|
if(!this.isStoreOk) return 'unavailable';
|
|
let status = this.options.status;
|
|
if(status === 'syncing' && !this.syncing) status = 'paused';
|
|
return status;
|
|
}
|
|
|
|
init()
|
|
{
|
|
this.commandScope = 'vectorizedpanel';
|
|
this.isLoading = false;
|
|
this.syncing = false;
|
|
this.syncingTimer = 0;
|
|
this.progressBarWidth = 700;
|
|
this.waitTime = 0;
|
|
this.syncCouter = 0;
|
|
|
|
let store = null;
|
|
if(window !== window.parent)
|
|
{
|
|
const zaiPanel = window.parent.zui.AIPanel.shared;
|
|
store = zaiPanel ? zaiPanel.store : null;
|
|
}
|
|
else if(this.options.zaiSetting)
|
|
{
|
|
try {
|
|
store = zui.ZentaoAIStore.createFromZentao(this.options.zaiSetting);
|
|
} catch (error) {
|
|
console.error('create zentao ai store failed', error);
|
|
}
|
|
}
|
|
|
|
this.store = store;
|
|
}
|
|
|
|
async afterInit()
|
|
{
|
|
this.$panel = this.$element.closest('.vectorized-panel');
|
|
|
|
this.toggleLoading();
|
|
if (this.store) this.isStoreOk = await this.store.isOK();
|
|
this.toggleLoading(false);
|
|
|
|
zui.bindCommands(this.$panel, {
|
|
scope: this.commandScope,
|
|
onCommand: this.executeCommand.bind(this),
|
|
});
|
|
|
|
this.render();
|
|
}
|
|
|
|
updateProgresses(status)
|
|
{
|
|
status = status || this.actualStatus;
|
|
const options = this.options;
|
|
const syncDetails = options.syncDetails || {};
|
|
const $progresses = this.$panel.find('.vectorized-progress');
|
|
const maxCount = Math.max(100, Object.values(syncDetails).reduce((maxVal, info) => {
|
|
maxVal = Math.max(maxVal, (info.failed || 0) + (info.synced || 0));
|
|
return maxVal;
|
|
}, 0));
|
|
const maxWidth = this.progressBarWidth || 600;
|
|
const syncing = !!this.syncing;
|
|
$progresses.each(function()
|
|
{
|
|
const $progress = $(this);
|
|
const type = $progress.data('type');
|
|
const info = syncDetails[type] || {failed: 0, synced: 0};
|
|
const isSyncing = type === options.syncingType && syncing;
|
|
const synced = info.synced || 0;
|
|
const failed = info.failed || 0;
|
|
const total = synced + failed;
|
|
$progress.toggleClass('is-syncing-type', isSyncing);
|
|
$progress.find('.vectorized-failed-info').toggleClass('hidden', !info.failed);
|
|
$progress.find('.vectorized-finished-count').text(synced);
|
|
$progress.find('.vectorized-failed-count').text(failed);
|
|
$progress.find('.vectorized-loading-icon').toggleClass('hidden', !isSyncing);
|
|
$progress.find('.vectorized-sync-type').toggleClass('font-bold', !!syncDetails[type]).toggleClass('text-gray', !syncDetails[type]).toggleClass('text-primary', isSyncing);
|
|
$progress.find('.vectorized-sync-progress').toggleClass('active progress-striped', isSyncing).css('width', Math.max(1, maxWidth * total / maxCount));
|
|
$progress.find('.progress-bar.is-synced').css('width', total ? `${100 * synced / total}%` : '1px');
|
|
$progress.find('.progress-bar.is-failed').css('width', total ? `${100 * failed / total}%` : '0');
|
|
});
|
|
}
|
|
|
|
render(newOptions)
|
|
{
|
|
super.render(newOptions);
|
|
|
|
const $panel = this.$panel;
|
|
const options = this.options;
|
|
const status = this.actualStatus;
|
|
const lang = options.langData;
|
|
const syncFailed = status === 'synced' && !this.options.syncedCount && !!this.options.syncFailedCount;
|
|
|
|
Object.keys(lang.vectorizedStatusList).forEach(statusType =>
|
|
{
|
|
$panel.toggleClass(`is-status-${statusType}`, status === statusType).toggleClass(`not-status-${statusType}`, status !== statusType);
|
|
});
|
|
|
|
$panel.removeClass('loading');
|
|
$panel.find('.vectorized-status').text(lang.vectorizedStatusList[syncFailed ? 'failed' : status]);
|
|
$panel.toggleClass('is-syncing-loop', !!this.syncing);
|
|
$panel.toggleClass('not-syncing-loop', !this.syncing);
|
|
$panel.toggleClass('is-synced-failed', syncFailed).toggleClass('not-synced-failed', !syncFailed);
|
|
$panel.find('.vectorized-finished-total-count').text(options.syncedCount);
|
|
$panel.find('.vectorized-failed-total-count').text(options.syncFailedCount);
|
|
$panel.find('.vectorized-last-sync-info').toggleClass('hidden', status !== 'paused' && status !== 'synced').find('.vectorized-last-sync-time').text(zui.formatDate(status === 'synced' ? (options.syncedTime || options.syncTime) : options.syncTime));
|
|
$panel.find('.vectorized-synced-with-failed').toggleClass('hidden', options.syncFailedCount === 0 || status !== 'synced');
|
|
|
|
this.updateProgresses();
|
|
}
|
|
|
|
executeCommand(context, params)
|
|
{
|
|
if(typeof context === 'string') context = {name: context};
|
|
if (!context.scope || context.scope === this.commandScope)
|
|
{
|
|
return zui.deepCall(this, context.name, params);
|
|
}
|
|
}
|
|
|
|
toggleLoading(loading)
|
|
{
|
|
loading = loading === undefined ? true : !!loading;
|
|
this.isLoading = loading;
|
|
this.$panel.toggleClass('loading', loading);
|
|
}
|
|
|
|
getLang(key)
|
|
{
|
|
return this.options.langData[key];
|
|
}
|
|
|
|
async request(url, options)
|
|
{
|
|
if(Array.isArray(url)) url = $.createLink.apply(null, url);
|
|
|
|
const result = await $.ajaxSubmit($.extend({url: url}, options));
|
|
const response = result[0];
|
|
const error = result[1];
|
|
if(!error && response && response.info) this.render(response.info);
|
|
|
|
return response;
|
|
}
|
|
|
|
async post(url, data, options)
|
|
{
|
|
return this.request(url, $.extend({method: 'POST', data: data}, options));
|
|
}
|
|
|
|
async enable()
|
|
{
|
|
this.toggleLoading(true);
|
|
const result = await this.post(['zai', 'ajaxEnableVectorization']);
|
|
this.toggleLoading(false);
|
|
if(result) return true;
|
|
}
|
|
|
|
async syncNext(data)
|
|
{
|
|
this.syncCouter++;
|
|
const result = await this.post(['zai', 'ajaxSyncVectorization'], data);
|
|
let waitTime = result.data.lastSync ? (result.data.lastSync.time * 3) : 100;
|
|
if(this.syncCouter % 200 === 0) waitTime += 2000;
|
|
if(this.syncCouter % 1000 === 0) waitTime += 2000;
|
|
await zui.delay(waitTime);
|
|
return result;
|
|
}
|
|
|
|
async sync(options)
|
|
{
|
|
this.syncing = true;
|
|
this.render();
|
|
|
|
const force = options && options.force;
|
|
const result = await this.syncNext({force: !!force});
|
|
if(!result || typeof result !== 'object')
|
|
{
|
|
zui.Messager.fail(this.getLang('syncRequestFailed'));
|
|
this.syncing = false;
|
|
this.render();
|
|
return;
|
|
}
|
|
if(result.result === 'failed')
|
|
{
|
|
this.syncing = false;
|
|
this.render(result.data);
|
|
return;
|
|
}
|
|
if(result.data)
|
|
{
|
|
if(result.data.status === 'synced')
|
|
{
|
|
this.syncing = false;
|
|
}
|
|
else
|
|
{
|
|
this.syncingTimer = setTimeout(() => {
|
|
this.syncingTimer = 0;
|
|
if(this.syncing) this.sync();
|
|
}, this.waitTime || 0);
|
|
}
|
|
this.render(result.data);
|
|
}
|
|
}
|
|
|
|
async startSync()
|
|
{
|
|
if(this.syncing) return;
|
|
this.sync();
|
|
}
|
|
|
|
resumeSync()
|
|
{
|
|
return this.startSync();
|
|
}
|
|
|
|
pauseSync()
|
|
{
|
|
if(this.syncingTimer)
|
|
{
|
|
clearTimeout(this.syncingTimer);
|
|
this.syncingTimer = 0;
|
|
}
|
|
this.syncing = false;
|
|
}
|
|
|
|
resync()
|
|
{
|
|
if(this.syncing) return;
|
|
return this.sync({force: true});
|
|
}
|
|
|
|
async resetSync()
|
|
{
|
|
const confirmed = await zui.Modal.confirm(this.getLang('confirmResetSync'));
|
|
if(!confirmed) return;
|
|
|
|
this.toggleLoading(true);
|
|
const result = await this.post(['zai', 'ajaxEnableVectorization'], {force: true});
|
|
this.toggleLoading(false);
|
|
return result;
|
|
}
|
|
|
|
destroy()
|
|
{
|
|
super.destroy();
|
|
zui.unbindCommands(this.$panel, this.commandScope);
|
|
}
|
|
};
|
|
|
|
VectorizedPanel.register();
|
|
|
|
window.updateVectorizedState = function($element)
|
|
{
|
|
const panel = $element.find('[z-use-vectorizedpanel]').zui();
|
|
if(panel) panel.render();
|
|
};
|