Files
YwxAppThink/public/static/backend/modules/appmarket.js
T

282 lines
13 KiB
JavaScript

layui.define(['http', 'setter', 'auth', 'form'], function (exports) {
var $ = layui.$, layer = layui.layer, http = layui.http, auth = layui.auth, form = layui.form;
var _perms = (layui.data('backend').permission) || [];
auth.init(_perms);
auth.setController('addon');
var isDemo = false;
function escapeHtml(s) {
return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) {
return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c];
});
}
function priceText(p) {
p = Number(p) || 0;
return p > 0 ? '¥' + p : '免费';
}
function cardHtml(item) {
var logo = item.logo
? '<img src="' + escapeHtml(item.logo) + '" class="m-logo">'
: '<div class="m-logo m-logo-default">' + escapeHtml((item.title || '?').charAt(0)) + '</div>';
var action;
if (item.installed) {
var btns = '<button class="layui-btn layui-btn-xs layui-btn-normal" data-act="manage" data-name="' + escapeHtml(item.name) + '">管理</button>';
if (item.upgradable) {
btns = '<button class="layui-btn layui-btn-xs layui-btn-warm" data-act="upgrade" data-name="' + escapeHtml(item.name) + '" data-version="' + escapeHtml(item.version) + '">升级 v' + escapeHtml(item.version) + '</button>' + btns;
}
if (Number(item.price) > 0) {
btns += '<button class="layui-btn layui-btn-xs layui-btn-danger" data-act="refund" data-name="' + escapeHtml(item.name) + '">退款</button>';
}
action = '<button class="layui-btn layui-btn-xs layui-btn-disabled" disabled>已安装</button>' + btns;
} else {
var label = (Number(item.price) > 0 ? '¥' + item.price + ' 购买安装' : '安装');
action = '<button class="layui-btn layui-btn-xs layui-btn-warm" data-act="install" data-name="' + escapeHtml(item.name) + '" data-version="' + escapeHtml(item.version) + '" data-price="' + Number(item.price || 0) + '">' + label + '</button>';
}
return '<div class="market-card">'
+ '<div class="m-head">' + logo + '<div class="m-meta"><div class="m-title">' + escapeHtml(item.title) + '</div><div class="m-author">' + escapeHtml(item.author || '') + ' · v' + escapeHtml(item.version || '') + '</div></div></div>'
+ '<div class="m-intro">' + escapeHtml(item.intro || '') + '</div>'
+ '<div class="m-foot"><span class="m-price ' + (Number(item.price) > 0 ? 'paid' : 'free') + '">' + priceText(item.price) + '</span>' + action + '</div>'
+ '</div>';
}
function render(list) {
var html = (list || []).map(cardHtml).join('');
$('#marketList').html(html || '<div class="empty">暂无可安装的插件</div>');
// 权限控制:无安装权限则隐藏安装按钮
if (!auth.has('addon:install') && !auth.has('addon:*')) {
$('[data-act="install"]').remove();
}
}
function load() {
http.get('market', {})
.then(function (res) {
if (res.code !== 0) {
layer.msg(res.message || '获取失败', { icon: 2 });
return;
}
isDemo = !!res.data.demo;
render(res.data.list || []);
})
.catch(function () {
layer.msg('请求失败', { icon: 2 });
});
}
$('#marketList').on('click', '[data-act="install"]', function () {
var $btn = $(this);
var name = $btn.data('name');
var version = $btn.data('version');
var price = Number($btn.data('price')) || 0;
var doInstall = function () {
if (isDemo) {
layer.msg('演示模式:已安装「' + name + '」', { icon: 1 });
$btn.parent().html('<button class="layui-btn layui-btn-xs layui-btn-disabled" disabled>已安装</button><button class="layui-btn layui-btn-xs layui-btn-normal" data-act="manage" data-name="' + name + '">管理</button>');
return;
}
var loading = layer.load();
http.post('downloadInstall', { name: name, version: version })
.then(function (res) {
layer.close(loading);
if (res.code === 0) {
layer.msg('安装成功', { icon: 1 });
load();
} else {
layer.msg(res.message || '安装失败', { icon: 2 });
}
})
.catch(function () {
layer.close(loading);
layer.msg('请求失败', { icon: 2 });
});
};
if (price > 0) {
layer.confirm('该付费插件授权绑定当前站点域名(' + location.host + '),换站点安装将被拒绝。确认在当前站点安装?', { title: '域名授权提示' }, function (idx) {
layer.close(idx);
doInstall();
});
} else {
doInstall();
}
});
$('#marketList').on('click', '[data-act="refund"]', function () {
var $btn = $(this);
var name = $btn.data('name');
layer.confirm('确认对插件「' + name + '」发起退款?退款后授权将被吊销,无法再下载或安装。', function (idx) {
layer.close(idx);
var loading = layer.load();
http.post('refund', { name: name })
.then(function (res) {
layer.close(loading);
if (res.code === 0) {
layer.msg('退款成功,授权已吊销', { icon: 1 });
load();
} else {
layer.msg(res.message || '退款失败', { icon: 2 });
}
})
.catch(function () {
layer.close(loading);
layer.msg('请求失败', { icon: 2 });
});
});
});
$('#marketList').on('click', '[data-act="upgrade"]', function () {
var $btn = $(this);
var name = $btn.data('name');
var version = $btn.data('version');
var loading = layer.load();
http.post('upgrade', { name: name, version: version })
.then(function (res) {
layer.close(loading);
if (res.code === 0) {
layer.msg('升级成功', { icon: 1 });
load();
} else {
layer.msg(res.message || '升级失败', { icon: 2 });
}
})
.catch(function () {
layer.close(loading);
layer.msg('请求失败', { icon: 2 });
});
});
$('#marketList').on('click', '[data-act="manage"]', function () {
var name = $(this).data('name');
if (isDemo) {
layer.msg('演示:进入「' + name + '」后台', { icon: 0 });
return;
}
// 真实模式:跳转到插件自己的后台(约定路径,可按实际调整)
window.open('/' + name);
});
// ===== 发布到本服务器(仅开发模式显示) =====
var isDev = $('#appDebug').val() === '1';
var installedList = [];
if (isDev) {
$('#btnPublish').show();
}
function loadInstalled() {
return http.get('index', { page: 1, limit: 9999 })
.then(function (res) {
if (res.code === 0 && Array.isArray(res.data)) {
installedList = res.data;
}
return installedList;
})
.catch(function () { return []; });
}
$('#btnPublish').on('click', function () {
loadInstalled().then(function (list) {
if (!list.length) {
layer.msg('暂无已安装插件可发布', { icon: 2 });
return;
}
var opts = list.map(function (it) {
return '<option value="' + escapeHtml(it.name) + '">' + escapeHtml(it.title || it.name) + ' v' + escapeHtml(it.version || '') + '</option>';
}).join('');
var html =
'<div style="padding:15px;"><div class="layui-form">'
+ '<div class="layui-form-item"><label class="layui-form-label">选择插件</label><div class="layui-input-block"><select id="pubName" class="layui-input">' + opts + '</select></div></div>'
+ '<div class="layui-form-item"><label class="layui-form-label">标题</label><div class="layui-input-block"><input id="pubTitle" class="layui-input"></div></div>'
+ '<div class="layui-form-item"><label class="layui-form-label">作者</label><div class="layui-input-block"><input id="pubAuthor" class="layui-input"></div></div>'
+ '<div class="layui-form-item"><label class="layui-form-label">简介</label><div class="layui-input-block"><textarea id="pubDesc" class="layui-input" rows="3"></textarea></div></div>'
+ '<div class="layui-form-item"><label class="layui-form-label">价格</label><div class="layui-input-block"><input id="pubPrice" type="number" step="0.01" value="0" class="layui-input"></div></div>'
+ '<div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn layui-btn-danger" id="pubSubmit">确认发布到本服务器</button></div></div>'
+ '</div></div>';
layer.open({ type: 1, title: '发布到本服务器市场', area: ['520px', 'auto'], content: html });
// 关键:下拉是动态注入到 .layui-form 内的元素,必须显式 render 才会显示选项,
// 否则 layui 增强后的 select 会显示为空(表现为「选择插件」没有任何内容)。
form.render('select');
function fillMeta() {
var name = $('#pubName').val();
var it = list.filter(function (x) { return x.name === name; })[0] || {};
$('#pubTitle').val(it.title || name);
$('#pubAuthor').val(it.author || '');
$('#pubDesc').val(it.description || it.intro || '');
$('#pubPrice').val(it.price != null ? it.price : 0);
}
fillMeta();
$('#pubName').on('change', fillMeta);
$('#pubSubmit').on('click', function () {
var data = {
name: $('#pubName').val(),
title: $('#pubTitle').val(),
author: $('#pubAuthor').val(),
description: $('#pubDesc').val(),
price: $('#pubPrice').val() || 0
};
var loading = layer.load();
http.post('publish', data)
.then(function (res) {
layer.close(loading);
if (res.code === 0) {
layer.msg('发布成功', { icon: 1 });
layer.closeAll();
load();
} else {
layer.msg(res.message || '发布失败', { icon: 2 });
}
})
.catch(function () {
layer.close(loading);
layer.msg('请求失败', { icon: 2 });
});
});
});
});
// ===== 发布到官方公共市场(需开发者令牌,服务端审核) =====
$('#btnSubmitOfficial').on('click', function () {
loadInstalled().then(function (list) {
if (!list.length) {
layer.msg('暂无已安装插件可发布', { icon: 2 });
return;
}
var opts = list.map(function (it) {
return '<option value="' + escapeHtml(it.name) + '">' + escapeHtml(it.title || it.name) + ' v' + escapeHtml(it.version || '') + '</option>';
}).join('');
var html =
'<div style="padding:15px;"><div class="layui-form">'
+ '<div class="layui-form-item"><label class="layui-form-label">选择插件</label><div class="layui-input-block"><select id="offName" class="layui-input">' + opts + '</select></div></div>'
+ '<div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn layui-btn-normal" id="offSubmit">提交审核</button></div></div>'
+ '</div></div>';
layer.open({ type: 1, title: '发布到官方市场(需审核)', area: ['520px', 'auto'], content: html });
form.render('select');
$('#offSubmit').on('click', function () {
var loading = layer.load();
http.post('submitOfficial', { name: $('#offName').val() })
.then(function (res) {
layer.close(loading);
if (res.code === 0) {
layer.msg(res.message || '提交成功,等待审核', { icon: 1 });
layer.closeAll();
} else {
layer.msg(res.message || '提交失败', { icon: 2 });
}
})
.catch(function () {
layer.close(loading);
layer.msg('请求失败', { icon: 2 });
});
});
});
});
load();
exports('market', {});
});