#20 add web-authorized

This commit is contained in:
新亮
2021-03-28 15:52:02 +08:00
parent 3e918fce59
commit 84cc0c9cbc
61 changed files with 6701 additions and 20 deletions

View File

@@ -0,0 +1,589 @@
/* ==========================================================
* bootstrap-maxlength.js v1.9.0
*
* Copyright (c) 2013-2020 Maurizio Napoleoni;
*
* Licensed under the terms of the MIT license.
* See: https://github.com/mimo84/bootstrap-maxlength/blob/master/LICENSE
* ========================================================== */
/*global jQuery*/
(function ($) {
'use strict';
/**
* We need an event when the elements are destroyed
* because if an input is removed, we have to remove the
* maxlength object associated (if any).
* From:
* http://stackoverflow.com/questions/2200494/jquery-trigger-event-when-an-element-is-removed-from-the-dom
*/
if (!$.event.special.destroyed) {
$.event.special.destroyed = {
remove: function (o) {
if (o.handler) {
o.handler();
}
}
};
}
$.fn.extend({
maxlength: function (options, callback) {
var documentBody = $('body'),
defaults = {
showOnReady: false, // true to always show when indicator is ready
alwaysShow: true, // if true the indicator it's always shown.
threshold: 0, // Represents how many chars left are needed to show up the counter
warningClass: 'small form-text text-muted',
limitReachedClass: 'small form-text text-danger',
separator: ' / ',
preText: '',
postText: '',
showMaxLength: true,
placement: 'bottom-right-inside',
message: null, // an alternative way to provide the message text
showCharsTyped: true, // show the number of characters typed and not the number of characters remaining
validate: false, // if the browser doesn't support the maxlength attribute, attempt to type more than the indicated chars, will be prevented.
utf8: false, // counts using bytesize rather than length. eg: '£' is counted as 2 characters.
appendToParent: false, // append the indicator to the input field's parent instead of body
twoCharLinebreak: true, // count linebreak as 2 characters to match IE/Chrome textarea validation. As well as DB storage.
customMaxAttribute: null, // null = use maxlength attribute and browser functionality, string = use specified attribute instead.
allowOverMax: false, // Form submit validation is handled on your own. when maxlength has been exceeded 'overmax' class added to element
zIndex: 1099
};
if ($.isFunction(options) && !callback) {
callback = options;
options = {};
}
options = $.extend(defaults, options);
/**
* Return the byte count of the specified character in UTF8 encoding.
* Note: This won't cover UTF-8 characters that are 4 bytes long.
*
* @param input
* @return {number}
*/
function utf8CharByteCount(character) {
var c = character.charCodeAt();
// Not c then 0, else c < 128 then 1, else c < 2048 then 2, else 3
return !c ? 0 : c < 128 ? 1 : c < 2048 ? 2 : 3;
}
/**
* Return the length of the specified input in UTF8 encoding.
*
* @param input
* @return {number}
*/
function utf8Length(string) {
return string.split("")
.map(utf8CharByteCount)
// Prevent reduce from throwing an error if the string is empty.
.concat(0)
.reduce(function (sum, val) {
return sum + val;
});
}
/**
* Return the length of the specified input.
*
* @param input
* @return {number}
*/
function inputLength(input) {
var text = input.val();
if (options.twoCharLinebreak) {
// Count all line breaks as 2 characters
text = text.replace(/\r(?!\n)|\n(?!\r)/g, '\r\n');
} else {
// Remove all double-character (\r\n) linebreaks, so they're counted only once.
text = text.replace(/(?:\r\n|\r|\n)/g, '\n');
}
var currentLength = 0;
if (options.utf8) {
currentLength = utf8Length(text);
} else {
currentLength = text.length;
}
// Remove "C:\fakepath\" from counter when using file input
// Fix https://github.com/mimo84/bootstrap-maxlength/issues/146
if (input.prop("type") === "file" && input.val() !== "") {
currentLength -= 12;
}
return currentLength;
}
/**
* Truncate the text of the specified input.
*
* @param input
* @param limit
*/
function truncateChars(input, maxlength) {
var text = input.val();
if (options.twoCharLinebreak) {
text = text.replace(/\r(?!\n)|\n(?!\r)/g, '\r\n');
if (text[text.length - 1] === '\n') {
maxlength -= text.length % 2;
}
}
if (options.utf8) {
var indexedSize = text.split("").map(utf8CharByteCount);
for (
var removedBytes = 0,
bytesPastMax = utf8Length(text) - maxlength; removedBytes < bytesPastMax; removedBytes += indexedSize.pop()
);
maxlength -= (maxlength - indexedSize.length);
}
input.val(text.substr(0, maxlength));
}
/**
* Return true if the indicator should be showing up.
*
* @param input
* @param threshold
* @param maxlength
* @return {number}
*/
function charsLeftThreshold(input, threshold, maxlength) {
var output = true;
if (!options.alwaysShow && (maxlength - inputLength(input) > threshold)) {
output = false;
}
return output;
}
/**
* Returns how many chars are left to complete the fill up of the form.
*
* @param input
* @param maxlength
* @return {number}
*/
function remainingChars(input, maxlength) {
var length = maxlength - inputLength(input);
return length;
}
/**
* When called displays the indicator.
*
* @param indicator
*/
function showRemaining(currentInput, indicator) {
indicator.css({
display: 'block'
});
currentInput.trigger('maxlength.shown');
}
/**
* When called shows the indicator.
*
* @param indicator
*/
function hideRemaining(currentInput, indicator) {
if (options.alwaysShow) {
return;
}
indicator.css({
display: 'none'
});
currentInput.trigger('maxlength.hidden');
}
/**
* This function updates the value in the indicator
*
* @param maxLengthThisInput
* @param typedChars
* @return String
*/
function updateMaxLengthHTML(currentInputText, maxLengthThisInput, typedChars) {
var output = '';
if (options.message) {
if (typeof options.message === 'function') {
output = options.message(currentInputText, maxLengthThisInput);
} else {
output = options.message.replace('%charsTyped%', typedChars)
.replace('%charsRemaining%', maxLengthThisInput - typedChars)
.replace('%charsTotal%', maxLengthThisInput);
}
} else {
if (options.preText) {
output += options.preText;
}
if (!options.showCharsTyped) {
output += maxLengthThisInput - typedChars;
} else {
output += typedChars;
}
if (options.showMaxLength) {
output += options.separator + maxLengthThisInput;
}
if (options.postText) {
output += options.postText;
}
}
return output;
}
/**
* This function updates the value of the counter in the indicator.
* Wants as parameters: the number of remaining chars, the element currently managed,
* the maxLength for the current input and the indicator generated for it.
*
* @param remaining
* @param currentInput
* @param maxLengthCurrentInput
* @param maxLengthIndicator
*/
function manageRemainingVisibility(remaining, currentInput, maxLengthCurrentInput, maxLengthIndicator) {
if (maxLengthIndicator) {
maxLengthIndicator.html(updateMaxLengthHTML(currentInput.val(), maxLengthCurrentInput, (maxLengthCurrentInput - remaining)));
if (remaining > 0) {
if (charsLeftThreshold(currentInput, options.threshold, maxLengthCurrentInput)) {
showRemaining(currentInput, maxLengthIndicator.removeClass(options.limitReachedClass).addClass(options.warningClass));
} else {
hideRemaining(currentInput, maxLengthIndicator);
}
} else {
showRemaining(currentInput, maxLengthIndicator.removeClass(options.warningClass).addClass(options.limitReachedClass));
}
}
if (options.customMaxAttribute) {
// class to use for form validation on custom maxlength attribute
if (remaining < 0) {
currentInput.addClass('overmax');
} else {
currentInput.removeClass('overmax');
}
}
}
/**
* This function returns an object containing all the
* informations about the position of the current input
*
* @param currentInput
* @return object {bottom height left right top width}
*
*/
function getPosition(currentInput) {
var el = currentInput[0];
return $.extend({}, (typeof el.getBoundingClientRect === 'function') ? el.getBoundingClientRect() : {
width: el.offsetWidth,
height: el.offsetHeight
}, currentInput.offset());
}
/**
* This function places the maxLengthIndicator based on placement config object.
*
* @param {object} placement
* @param {$} maxLengthIndicator
* @return null
*
*/
function placeWithCSS(placement, maxLengthIndicator) {
if (!placement || !maxLengthIndicator) {
return;
}
var POSITION_KEYS = [
'top',
'bottom',
'left',
'right',
'position'
];
var cssPos = {};
// filter css properties to position
$.each(POSITION_KEYS, function (i, key) {
var val = options.placement[key];
if (typeof val !== 'undefined') {
cssPos[key] = val;
}
});
maxLengthIndicator.css(cssPos);
return;
}
/**
* This function places the maxLengthIndicator at the
* top / bottom / left / right of the currentInput
*
* @param currentInput
* @param maxLengthIndicator
* @return null
*
*/
function place(currentInput, maxLengthIndicator) {
var pos = getPosition(currentInput);
// Supports custom placement handler
if ($.type(options.placement) === 'function') {
options.placement(currentInput, maxLengthIndicator, pos);
return;
}
// Supports custom placement via css positional properties
if ($.isPlainObject(options.placement)) {
placeWithCSS(options.placement, maxLengthIndicator);
return;
}
var inputOuter = currentInput.outerWidth(),
outerWidth = maxLengthIndicator.outerWidth(),
actualWidth = maxLengthIndicator.width(),
actualHeight = maxLengthIndicator.height();
// get the right position if the indicator is appended to the input's parent
if (options.appendToParent) {
pos.top -= currentInput.parent().offset().top;
pos.left -= currentInput.parent().offset().left;
}
switch (options.placement) {
case 'bottom':
maxLengthIndicator.css({
top: pos.top + pos.height,
left: pos.left + pos.width / 2 - actualWidth / 2
});
break;
case 'top':
maxLengthIndicator.css({
top: pos.top - actualHeight,
left: pos.left + pos.width / 2 - actualWidth / 2
});
break;
case 'left':
maxLengthIndicator.css({
top: pos.top + pos.height / 2 - actualHeight / 2,
left: pos.left - actualWidth
});
break;
case 'right':
maxLengthIndicator.css({
top: pos.top + pos.height / 2 - actualHeight / 2,
left: pos.left + pos.width
});
break;
case 'bottom-right':
maxLengthIndicator.css({
top: pos.top + pos.height,
left: pos.left + pos.width
});
break;
case 'top-right':
maxLengthIndicator.css({
top: pos.top - actualHeight,
left: pos.left + inputOuter
});
break;
case 'top-left':
maxLengthIndicator.css({
top: pos.top - actualHeight,
left: pos.left - outerWidth
});
break;
case 'bottom-left':
maxLengthIndicator.css({
top: pos.top + currentInput.outerHeight(),
left: pos.left - outerWidth
});
break;
case 'centered-right':
maxLengthIndicator.css({
top: pos.top + (actualHeight / 2),
left: pos.left + inputOuter - outerWidth - 3
});
break;
// Some more options for placements
case 'bottom-right-inside':
maxLengthIndicator.css({
top: pos.top + pos.height,
left: pos.left + pos.width - outerWidth
});
break;
case 'top-right-inside':
maxLengthIndicator.css({
top: pos.top - actualHeight,
left: pos.left + inputOuter - outerWidth
});
break;
case 'top-left-inside':
maxLengthIndicator.css({
top: pos.top - actualHeight,
left: pos.left
});
break;
case 'bottom-left-inside':
maxLengthIndicator.css({
top: pos.top + currentInput.outerHeight(),
left: pos.left
});
break;
}
}
/**
* This function returns true if the indicator position needs to
* be recalculated when the currentInput changes
*
* @return {boolean}
*
*/
function isPlacementMutable() {
return options.placement === 'bottom-right-inside' || options.placement === 'top-right-inside' || typeof options.placement === 'function' || (options.message && typeof options.message === 'function');
}
/**
* This function retrieves the maximum length of currentInput
*
* @param currentInput
* @return {number}
*
*/
function getMaxLength(currentInput) {
var max = currentInput.attr('maxlength') || options.customMaxAttribute;
if (options.customMaxAttribute && !options.allowOverMax) {
var custom = currentInput.attr(options.customMaxAttribute);
if (!max || custom < max) {
max = custom;
}
}
if (!max) {
max = currentInput.attr('size');
}
return max;
}
return this.each(function () {
var currentInput = $(this),
maxLengthCurrentInput,
maxLengthIndicator;
$(window).resize(function () {
if (maxLengthIndicator) {
place(currentInput, maxLengthIndicator);
}
});
function firstInit() {
var maxlengthContent = updateMaxLengthHTML(currentInput.val(), maxLengthCurrentInput, '0');
maxLengthCurrentInput = getMaxLength(currentInput);
if (!maxLengthIndicator) {
maxLengthIndicator = $('<span class="bootstrap-maxlength"></span>').css({
display: 'none',
position: 'absolute',
whiteSpace: 'nowrap',
zIndex: options.zIndex
}).html(maxlengthContent);
}
// We need to detect resizes if we are dealing with a textarea:
if (currentInput.is('textarea')) {
currentInput.data('maxlenghtsizex', currentInput.outerWidth());
currentInput.data('maxlenghtsizey', currentInput.outerHeight());
currentInput.mouseup(function () {
if (currentInput.outerWidth() !== currentInput.data('maxlenghtsizex') || currentInput.outerHeight() !== currentInput.data('maxlenghtsizey')) {
place(currentInput, maxLengthIndicator);
}
currentInput.data('maxlenghtsizex', currentInput.outerWidth());
currentInput.data('maxlenghtsizey', currentInput.outerHeight());
});
}
if (options.appendToParent) {
currentInput.parent().append(maxLengthIndicator);
currentInput.parent().css('position', 'relative');
} else {
documentBody.append(maxLengthIndicator);
}
var remaining = remainingChars(currentInput, getMaxLength(currentInput));
manageRemainingVisibility(remaining, currentInput, maxLengthCurrentInput, maxLengthIndicator);
place(currentInput, maxLengthIndicator);
}
if (options.showOnReady) {
currentInput.ready(function () {
firstInit();
});
} else {
currentInput.focus(function () {
firstInit();
});
}
currentInput.on('maxlength.reposition', function () {
place(currentInput, maxLengthIndicator);
});
currentInput.on('destroyed', function () {
if (maxLengthIndicator) {
maxLengthIndicator.remove();
}
});
currentInput.on('blur', function () {
if (maxLengthIndicator && !options.showOnReady) {
maxLengthIndicator.remove();
}
});
currentInput.on('input', function () {
var maxlength = getMaxLength(currentInput),
remaining = remainingChars(currentInput, maxlength),
output = true;
if (options.validate && remaining < 0) {
truncateChars(currentInput, maxlength);
output = false;
} else {
manageRemainingVisibility(remaining, currentInput, maxLengthCurrentInput, maxLengthIndicator);
}
if (isPlacementMutable()) {
place(currentInput, maxLengthIndicator);
}
return output;
});
});
}
});
}(jQuery));

View File

@@ -113,7 +113,7 @@
// 选项卡
$('#iframe-content').multitabs({
iframe : true,
refresh : 'no', // iframe中页面是否刷新'no''从不刷新''nav''点击菜单刷新''all''菜单和tab点击都刷新'
refresh : 'nav', // iframe中页面是否刷新'no''从不刷新''nav''点击菜单刷新''all''菜单和tab点击都刷新'
nav: {
backgroundColor: '#ffffff',
maxTabs : 35, // 选项卡最大值

View File

@@ -0,0 +1,292 @@
/**
* pagination.js 1.5.1
* A jQuery plugin to provide simple yet fully customisable pagination.
* @version 1.5.1
* @author mss
* @url https://github.com/Maxiaoxiang/jQuery-plugins
*
* @调用方法
* $(selector).pagination(option, callback);
* -此处callback是初始化调用option里的callback是点击页码后调用
*
* -- example --
* $(selector).pagination({
* ... // 配置参数
* callback: function(api) {
* console.log('点击页码调用该回调'); //切换页码时执行一次回调
* }
* }, function(){
* console.log('初始化'); //插件初始化时调用该方法,比如请求第一次接口来初始化分页配置
* });
*/
;
(function (factory) {
if (typeof define === "function" && (define.amd || define.cmd) && !jQuery) {
// AMD或CMD
define(["jquery"], factory);
} else if (typeof module === 'object' && module.exports) {
// Node/CommonJS
module.exports = function (root, jQuery) {
if (jQuery === undefined) {
if (typeof window !== 'undefined') {
jQuery = require('jquery');
} else {
jQuery = require('jquery')(root);
}
}
factory(jQuery);
return jQuery;
};
} else {
//Browser globals
factory(jQuery);
}
}(function ($) {
//配置参数
var defaults = {
totalData: 0, //数据总条数
showData: 0, //每页显示的条数
pageCount: 9, //总页数,默认为9
current: 1, //当前第几页
prevCls: 'prev', //上一页class
nextCls: 'next', //下一页class
prevContent: '<', //上一页内容
nextContent: '>', //下一页内容
activeCls: 'active', //当前页选中状态
coping: false, //首页和尾页
isHide: false, //当前页数为0页或者1页时不显示分页
homePage: '', //首页节点内容
endPage: '', //尾页节点内容
keepShowPN: false, //是否一直显示上一页下一页
mode: 'unfixed', //分页模式unfixed不固定页码数量fixed固定页码数量
count: 4, //mode为unfixed时显示当前选中页前后页数mode为fixed显示页码总数
jump: false, //跳转到指定页数
jumpIptCls: 'jump-ipt', //文本框内容
jumpBtnCls: 'jump-btn', //跳转按钮
jumpBtn: '跳转', //跳转按钮文本
callback: function () {} //回调
};
var Pagination = function (element, options) {
//全局变量
var opts = options, //配置
current, //当前页
$document = $(document),
$obj = $(element); //容器
/**
* 设置总页数
* @param {int} page 页码
* @return opts.pageCount 总页数配置
*/
this.setPageCount = function (page) {
return opts.pageCount = page;
};
/**
* 获取总页数
* 如果配置了总条数和每页显示条数,将会自动计算总页数并略过总页数配置,反之
* @return {int} 总页数
*/
this.getPageCount = function () {
return opts.totalData && opts.showData ? Math.ceil(parseInt(opts.totalData) / opts.showData) : opts.pageCount;
};
/**
* 获取当前页
* @return {int} 当前页码
*/
this.getCurrent = function () {
return current;
};
/**
* 填充数据
* @param {int} 页码
*/
this.filling = function (index) {
var html = '';
current = parseInt(index) || parseInt(opts.current); //当前页码
var pageCount = this.getPageCount(); //获取的总页数
switch (opts.mode) { //配置模式
case 'fixed': //固定按钮模式
html += '<li class="page-item"><a href="javascript:;" class="page-link ' + opts.prevCls + '">' + opts.prevContent + '</a></li>';
if (opts.coping) {
var home = opts.coping && opts.homePage ? opts.homePage : '1';
html += '<li class="page-item"><a class="page-link" href="javascript:;" data-page="1">' + home + '</a></li>';
}
var start = current > opts.count - 1 ? current + opts.count - 1 > pageCount ? current - (opts.count - (pageCount - current)) : current - 2 : 1;
var end = current + opts.count - 1 > pageCount ? pageCount : start + opts.count;
for (; start <= end; start++) {
if (start != current) {
html += '<li class="page-item"><a class="page-link" href="javascript:;" data-page="' + start + '">' + start + '</a></li>';
} else {
html += '<li class="page-item active"><span class="page-link ' + opts.activeCls + '">' + start + '</span></li>';
}
}
if (opts.coping) {
var _end = opts.coping && opts.endPage ? opts.endPage : pageCount;
html += '<li class="page-item"><a class="page-link" href="javascript:;" data-page="' + pageCount + '">' + _end + '</a></li>';
}
html += '<li class="page-item"><a href="javascript:;" class="page-link ' + opts.nextCls + '">' + opts.nextContent + '</a></li>';
break;
// if (opts.keepShowPN || current > 1) { //上一页
// html += '<a href="javascript:;" class="' + opts.prevCls + '">' + opts.prevContent + '</a>';
// } else {
// if (opts.keepShowPN == false) {
// $obj.find('.' + opts.prevCls) && $obj.find('.' + opts.prevCls).remove();
// }
// }
// if (current >= opts.count + 2 && current != 1 && pageCount != opts.count) {
// var home = opts.coping && opts.homePage ? opts.homePage : '1';
// html += opts.coping ? '<a href="javascript:;" data-page="1">' + home + '</a><span>...</span>' : '';
// }
// var start = (current - opts.count) <= 1 ? 1 : (current - opts.count);
// var end = (current + opts.count) >= pageCount ? pageCount : (current + opts.count);
// for (; start <= end; start++) {
// if (start <= pageCount && start >= 1) {
// if (start != current) {
// html += '<a href="javascript:;" data-page="' + start + '">' + start + '</a>';
// } else {
// html += '<span class="' + opts.activeCls + '">' + start + '</span>';
// }
// }
// }
// if (current + opts.count < pageCount && current >= 1 && pageCount > opts.count) {
// var end = opts.coping && opts.endPage ? opts.endPage : pageCount;
// html += opts.coping ? '<span>...</span><a href="javascript:;" data-page="' + pageCount + '">' + end + '</a>' : '';
// }
// if (opts.keepShowPN || current < pageCount) { //下一页
// html += '<a href="javascript:;" class="' + opts.nextCls + '">' + opts.nextContent + '</a>';
// } else {
// if (opts.keepShowPN == false) {
// $obj.find('.' + opts.nextCls) && $obj.find('.' + opts.nextCls).remove();
// }
// }
// break;
case 'unfixed': //不固定按钮模式
if (opts.keepShowPN || current > 1) { //上一页
html += '<a href="javascript:;" class="' + opts.prevCls + '">' + opts.prevContent + '</a>';
} else {
if (opts.keepShowPN == false) {
$obj.find('.' + opts.prevCls) && $obj.find('.' + opts.prevCls).remove();
}
}
if (current >= opts.count + 2 && current != 1 && pageCount != opts.count) {
var home = opts.coping && opts.homePage ? opts.homePage : '1';
html += opts.coping ? '<a href="javascript:;" data-page="1">' + home + '</a><span>...</span>' : '';
}
var start = (current - opts.count) <= 1 ? 1 : (current - opts.count);
var end = (current + opts.count) >= pageCount ? pageCount : (current + opts.count);
for (; start <= end; start++) {
if (start <= pageCount && start >= 1) {
if (start != current) {
html += '<a href="javascript:;" data-page="' + start + '">' + start + '</a>';
} else {
html += '<span class="' + opts.activeCls + '">' + start + '</span>';
}
}
}
if (current + opts.count < pageCount && current >= 1 && pageCount > opts.count) {
var end = opts.coping && opts.endPage ? opts.endPage : pageCount;
html += opts.coping ? '<span>...</span><a href="javascript:;" data-page="' + pageCount + '">' + end + '</a>' : '';
}
if (opts.keepShowPN || current < pageCount) { //下一页
html += '<a href="javascript:;" class="' + opts.nextCls + '">' + opts.nextContent + '</a>';
} else {
if (opts.keepShowPN == false) {
$obj.find('.' + opts.nextCls) && $obj.find('.' + opts.nextCls).remove();
}
}
break;
case 'easy': //简单模式
break;
default:
}
html += opts.jump ? '<input type="text" class="' + opts.jumpIptCls + '"><a href="javascript:;" class="' + opts.jumpBtnCls + '">' + opts.jumpBtn + '</a>' : '';
$obj.empty().html(html);
};
//绑定事件
this.eventBind = function () {
var that = this;
var pageCount = that.getPageCount(); //总页数
var index = 1;
$obj.off().on('click', 'a', function () {
if ($(this).hasClass(opts.nextCls)) {
if (parseInt($obj.find('.' + opts.activeCls).text()) >= pageCount) {
$(this).addClass('disabled');
return false;
} else {
index = parseInt($obj.find('.' + opts.activeCls).text()) + 1;
}
} else if ($(this).hasClass(opts.prevCls)) {
if (parseInt($obj.find('.' + opts.activeCls).text()) <= 1) {
$(this).addClass('disabled');
return false;
} else {
index = parseInt($obj.find('.' + opts.activeCls).text()) - 1;
}
} else if ($(this).hasClass(opts.jumpBtnCls)) {
if ($obj.find('.' + opts.jumpIptCls).val() !== '') {
index = parseInt($obj.find('.' + opts.jumpIptCls).val());
} else {
return;
}
} else {
index = parseInt($(this).data('page'));
}
that.filling(index);
typeof opts.callback === 'function' && opts.callback(that);
});
//输入跳转的页码
$obj.on('input propertychange', '.' + opts.jumpIptCls, function () {
var $this = $(this);
var val = $this.val();
var reg = /[^\d]/g;
if (reg.test(val)) $this.val(val.replace(reg, ''));
(parseInt(val) > pageCount) && $this.val(pageCount);
if (parseInt(val) === 0) $this.val(1); //最小值为1
});
//回车跳转指定页码
$document.keydown(function (e) {
if (e.keyCode == 13 && $obj.find('.' + opts.jumpIptCls).val()) {
var index = parseInt($obj.find('.' + opts.jumpIptCls).val());
that.filling(index);
typeof opts.callback === 'function' && opts.callback(that);
}
});
};
//初始化
this.init = function () {
this.filling(opts.current);
this.eventBind();
if (opts.isHide && this.getPageCount() == '1' || this.getPageCount() == '0') {
$obj.hide();
} else {
$obj.show();
}
};
this.init();
};
$.fn.pagination = function (parameter, callback) {
if (typeof parameter == 'function') { //重载
callback = parameter;
parameter = {};
} else {
parameter = parameter || {};
callback = callback || function () {};
}
var options = $.extend({}, defaults, parameter);
return this.each(function () {
var pagination = new Pagination(this, options);
callback(pagination);
});
};
}));

View File

@@ -0,0 +1,34 @@
function IsJson(str) {
if (typeof str == 'string') {
try {
var obj = JSON.parse(str);
if (typeof obj == 'object' && obj) {
return true;
} else {
return false;
}
} catch (e) {
console.log('error' + str + '!!!' + e);
return false;
}
}
console.log('It is not a string!')
}
function AjaxError(response) {
var errCode = response.status;
var errMsg = response.responseText;
if (IsJson(response.responseText)) {
const errInfo = JSON.parse(response.responseText);
errCode = errInfo.code;
errMsg = errInfo.message;
}
$.alert({
title: '错误提示',
icon: 'mdi mdi-alert',
type: 'red',
content: '错误码:' + errCode + '<br/>' + '错误信息:' + errMsg,
});
}

View File

@@ -0,0 +1,138 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
<div class="container-fluid p-t-15">
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-header">
<div class="card-title">新增调用方</div>
</div>
<div class="card-body">
<form>
<div class="form-group">
<label for="formGroupExampleInput">调用方</label>
<input type="text" class="form-control" maxlength="25" id="business_key"
placeholder="请输入调用方标识">
</div>
<div class="form-group">
<label for="formGroupExampleInput2">调用方对接人</label>
<input type="text" class="form-control" maxlength="50" id="business_developer"
placeholder="请输入调用方对接人">
</div>
<div class="form-group">
<label for="exampleFormControlTextarea1">备注</label>
<textarea class="form-control" maxlength="225" rows="3" id="remark"
placeholder="备注"></textarea>
</div>
<button type="button" id="btnOk" class="btn btn-primary">确认</button>
<button type="button" id="btnLoading" class="btn btn-primary" disabled style="display: none">
<span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true"></span>
执行中...
</button>
</form>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/util.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$("input#business_key").maxlength({
warningClass: "badge badge-info",
limitReachedClass: "badge badge-warning"
});
$("input#business_developer").maxlength({
warningClass: "badge badge-info",
limitReachedClass: "badge badge-warning"
});
$("textarea#remark").maxlength({
threshold: 255,
warningClass: "badge badge-info",
limitReachedClass: "badge badge-warning"
});
$('#btnOk').on('click', function () {
const businessKey = $("#business_key").val();
if (businessKey === "") {
$.alert({
title: '温馨提示',
icon: 'mdi mdi-alert',
type: 'orange',
content: '请输入调用方标识。',
});
return false;
}
const businessDeveloper = $("#business_developer").val();
if (businessDeveloper === "") {
$.alert({
title: '温馨提示',
icon: 'mdi mdi-alert',
type: 'orange',
content: '请输入调用方对接人。',
});
return false;
}
const remark = $("#remark").val();
$(this).hide();
$("#btnLoading").show();
const postData = {
business_key: businessKey,
business_developer: businessDeveloper,
remark: remark,
};
$.post("/api/authorized", JSON.stringify(postData), function (data) {
$("#btnLoading").hide();
$("#btnOk").show();
$.alert({
title: '操作成功',
icon: 'mdi mdi-check-decagram',
type: 'green',
content: '编号:' + data.id + ' 创建完成。',
buttons: {
okay: {
text: '关闭',
action: function () {
location.href = "/authorized/list";
}
}
}
});
}).fail(function (response) {
$("#btnLoading").hide();
$("#btnOk").show();
AjaxError(response);
})
});
})
</script>
</body>
</html>

View File

@@ -0,0 +1,226 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/js/bootstrap-multitabs/multitabs.min.css" rel="stylesheet" type="text/css">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
<div class="container-fluid p-t-15">
<div class="row">
<div class="col-lg-6">
<div class="card">
<div class="card-header">
<div class="card-title">接口授权</div>
</div>
<div class="card-body">
<div class="alert alert-warning" role="alert">
接口地址支持通配符(*),其中 * 表示 1 级,** 表示 n 级。
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<label class="input-group-text" for="request_method">选择请求方式</label>
</div>
<select class="custom-select" id="request_method">
<option value="GET">GET</option>
<option value="POST">POST</option>
<option value="PUT">PUT</option>
<option value="DELETE">DELETE</option>
<option value="PATCH">PATCH</option>
</select>
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="inputGroup-sizing-default">输入接口地址</span>
</div>
<input type="text" class="form-control" maxlength="60" id="request_api"
placeholder="接口地址">
</div>
<button type="button" id="btnOk" class="btn btn-primary">确认</button>
<button type="button" id="btnLoading" class="btn btn-primary" disabled style="display: none">
<span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true"></span>
执行中...
</button>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="card">
<header class="card-header">
<div class="card-title">已授权接口</div>
</header>
<div class="card-body apis">
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-multitabs/multitabs.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/util.js"></script>
<script type="text/javascript">
$(document).ready(function () {
const hash_id = {{ .HashID }}
$("input#request_api").maxlength({
warningClass: "badge badge-info",
limitReachedClass: "badge badge-warning"
});
// 加载列表页数据
getListData();
function getListData() {
$.get("/api/authorized_list", {id: hash_id}, function (data) {
// 成功
if (data.list.length > 0) {
$.each(data.list, function (index, value) {
const p = '<p>\n' +
'<a href="#!" data-id="' + value.hash_id + '" data-api="' + value.api + '" class="del">' +
'<span class="badge badge-secondary"><i class="mdi mdi-window-close"></i></span>\n' +
'</a>\n' +
'<span class="badge badge-success">' + value.method + '</span>\n' + value.api
;
$(".apis").append(p);
})
} else {
// 数据为空
const p = '<p>暂无授权接口</p>';
$(".apis").append(p);
}
}).fail(function (response) {
// 失败
AjaxError(response);
})
}
$('#btnOk').on('click', function () {
const requestMethod = $("#request_method").val();
const requestApi = $("#request_api").val();
if (requestMethod === "") {
$.alert({
title: '温馨提示',
icon: 'mdi mdi-alert',
type: 'orange',
content: '请选择请求方式。',
});
return false;
}
if (requestApi === "") {
$.alert({
title: '温馨提示',
icon: 'mdi mdi-alert',
type: 'orange',
content: '请输入请求地址。',
});
return false;
}
$(this).hide();
$("#btnLoading").show();
const postData = {
method: requestMethod,
api: requestApi,
id: hash_id,
};
$.post("/api/authorized_api", JSON.stringify(postData), function () {
$("#btnLoading").hide();
$("#btnOk").show();
$.alert({
title: '操作成功',
icon: 'mdi mdi-check-decagram',
type: 'green',
content: '接口:' + requestApi + ' 授权完成。',
buttons: {
okay: {
text: '关闭',
action: function () {
location.reload();
}
}
}
});
}).fail(function (response) {
$("#btnLoading").hide();
$("#btnOk").show();
AjaxError(response);
})
});
$(document).on('click', '.del', function () {
const id = $(this).attr('data-id');
const api = $(this).attr('data-api');
$.confirm({
title: '谨慎操作',
content: '确认要 <strong style="color: red">取消授权</strong> 吗?',
icon: 'mdi mdi-alert',
animation: 'scale',
closeAnimation: 'zoom',
buttons: {
okay: {
text: '确认',
keys: ['enter'],
btnClass: 'btn-orange',
action: function () {
$.ajax({
url: '/api/authorized_api/' + id,
type: 'DELETE',
success: function () {
$.alert({
title: '操作成功',
icon: 'mdi mdi-check-decagram',
type: 'green',
content: '接口:' + api + ' 已取消授权。',
buttons: {
okay: {
text: '关闭',
action: function () {
location.reload();
}
}
}
});
},
error: function (response) {
AjaxError(response);
},
});
}
},
cancel: {
text: '取消',
keys: ['ctrl', 'shift'],
}
}
});
})
})
</script>
</body>
</html>

View File

@@ -0,0 +1,286 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
<div class="container-fluid p-t-15">
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-toolbar d-flex flex-column flex-md-row">
<div class="toolbar-btn-action">
<a class="btn btn-primary m-r-5" href="/authorized/add"><i class="mdi mdi-plus"></i> 新增</a>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>编号</th>
<th>调用方</th>
<th>对接人</th>
<th>创建日期</th>
<th>更新日期</th>
<th style="text-align: center; ">状态</th>
<th style="text-align: center; ">操作</th>
</tr>
</thead>
<tbody class="tbody">
</tbody>
</table>
</div>
<ul class="pagination">
<ul class="pagination" id="paginationDiv">
</ul>
</ul>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/util.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery.pagination.js"></script>
<script type="text/javascript">
$(document).ready(function () {
// 加载列表页数据
getPageListData();
function getPageListData(page, page_size) {
if (parseInt(page) < 1) {
page = 1;
}
if (parseInt(page_size) < 1) {
page_size = 10;
}
$.get("/api/authorized", {page: page, page_size: page_size}, function (data) {
// 成功
if (data.list.length > 0) {
var totalNum = data.pagination.total; //总条数
var pageNum = Math.ceil(totalNum / data.pagination.pre_page_count); //分页的总页数
$("#paginationDiv").pagination({
current: data.pagination.current_page,
pageCount: pageNum,
coping: true,
homePage: '首页',
endPage: '末页',
mode: 'fixed',
prevContent: '上一页',
nextContent: '下一页',
activeCls: 'pageActive',
prevCls: 'pagePrev',
nextCls: 'pageNext',
callback: function (api) {
$(".tbody").html("");
getPageListData(api.getCurrent());
}
});
$.each(data.list, function (index, value) {
var showUsedBadge = "";
var optionUsedName = "";
if (value.is_used === 1) {
optionUsedName = '禁用';
showUsedBadge = '<span class="badge badge-success">启用</span></td>'
}
if (value.is_used === -1) {
optionUsedName = '启用';
showUsedBadge = '<span class="badge badge-danger">禁用</span></td>'
}
const tr = '<tr>\n' +
'<td>' + value.id + '</td>\n' +
'<td>' + value.business_key + '</td>\n' +
'<td>' + value.business_developer + '</td>\n' +
'<td>' + value.created_at + '</td>\n' +
'<td>' + value.updated_at + '</td>\n' +
'<td style="text-align: center; ">' + showUsedBadge + '</td>\n' +
'<td style="text-align: center; ">\n' +
'<div class="btn-group">\n' +
' <a class="btn btn-xs btn-default btn-detail" href="#!" title=""\n' +
' data-business-key="' + value.business_key + '"' +
' data-business-secret="' + value.business_secret + '"' +
' data-remark="' + value.remark + '"' +
' data-toggle="tooltip" data-original-title="详情">详情</a>\n' +
' <a class="btn btn-xs btn-default btn-option" href="#!" title=""\n' +
' data-id="' + value.hashid + '"' +
' data-is-used="' + value.is_used + '"' +
' data-toggle="tooltip" data-original-title="' + optionUsedName + '">' + optionUsedName + '</a>\n' +
' <a class="btn btn-xs btn-default" href="/authorized/api/'+value.hashid+'" title=""\n' +
' data-toggle="tooltip" data-original-title="接口">接口</a>\n' +
' <a class="btn btn-xs btn-default btn-confirm" href="#!" title=""\n' +
' data-id="' + value.hashid + '"' +
' data-toggle="tooltip" data-original-title="删除">删除</a>\n' +
'</div>\n' +
'</td>\n' +
'</tr>';
$(".tbody").append(tr);
})
} else {
// 数据为空
const tr = '<tr><td colspan="7" style="text-align: center">暂无数据</td></tr>';
$(".tbody").append(tr);
}
}).fail(function (response) {
// 失败
AjaxError(response);
})
}
// 详情
$(document).on('click', '.btn-detail', function () {
const business_key = $(this).attr('data-business-key');
const business_secret = $(this).attr('data-business-secret');
const business_remark = $(this).attr('data-remark');
$.alert({
title: '详情',
content: '调用方 KEY ' + business_key + '<br/>调用方 SECRET ' + business_secret + '<br/>备注:' + business_remark,
type: 'green',
animation: 'scale',
draggable: true,
});
});
// 启用/禁用
$(document).on('click', '.btn-option', function () {
const id = $(this).attr('data-id');
const isUsed = $(this).attr('data-is-used');
var tipMessage = "";
var wantUsed = 0;
if (isUsed === "1") { // 1=当前为启用状态,需要改成禁用
tipMessage = "禁用";
wantUsed = -1;
}
if (isUsed === "-1") { // -1=当前为禁用状态,需要改成启用
tipMessage = "启用";
wantUsed = 1;
}
const patchData = {
id: id,
used: wantUsed,
};
$.confirm({
title: '谨慎操作',
content: '确认要 <strong style="color: red">' + tipMessage + '</strong> 吗?',
icon: 'mdi mdi-alert',
animation: 'scale',
closeAnimation: 'zoom',
buttons: {
okay: {
text: '确认',
keys: ['enter'],
btnClass: 'btn-orange',
action: function () {
$.ajax({
url: '/api/authorized/used',
type: 'PATCH',
data: JSON.stringify(patchData),
success: function (result) {
$.alert({
title: '操作成功',
icon: 'mdi mdi-check-decagram',
type: 'green',
content: '编号:' + result.id + ' 已' + tipMessage + '。',
buttons: {
okay: {
text: '关闭',
action: function () {
location.reload();
}
}
}
});
},
error: function (response) {
AjaxError(response);
}
});
}
},
cancel: {
text: '取消',
keys: ['ctrl', 'shift'],
}
}
});
});
// 删除
$(document).on('click', '.btn-confirm', function () {
const id = $(this).attr('data-id');
$.confirm({
title: '谨慎操作',
content: '确认要 <strong style="color: red">删除</strong> 吗?',
icon: 'mdi mdi-alert',
animation: 'scale',
closeAnimation: 'zoom',
buttons: {
okay: {
text: '确认',
keys: ['enter'],
btnClass: 'btn-orange',
action: function () {
$.ajax({
url: '/api/authorized/' + id,
type: 'DELETE',
success: function (result) {
$.alert({
title: '操作成功',
icon: 'mdi mdi-check-decagram',
type: 'green',
content: '编号:' + result.id + ' 已删除。',
buttons: {
okay: {
text: '关闭',
action: function () {
location.reload();
}
}
}
});
},
error: function (response) {
AjaxError(response);
},
});
}
},
cancel: {
text: '取消',
keys: ['ctrl', 'shift'],
}
}
});
})
})
</script>
</body>
</html>

View File

@@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<link href="bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="bootstrap/css/style.min.css" rel="stylesheet">
</head>
@@ -16,9 +17,9 @@
<div class="card-body">
<div class="callout callout-warning mb-3">注意:请在 <code>Mac</code><code>Linux</code> 环境执行。</div>
<p>初始化项目所需信息:</p>
<p><i class="mdi mdi-checkbox-marked-circle"></i> <span>MySQL 数据表:<code>user_demo</code> </span></p>
<p><i class="mdi mdi-checkbox-marked-circle"></i> <span>MySQL 数据表:<code>authorized</code> </span></p>
<p><i class="mdi mdi-checkbox-marked-circle"></i> <span>MySQL 数据表:<code>authorized_api</code> </span></p>
<p>
<button type="button" id="btnOk" class="btn btn-primary">确认</button>
<button type="button" id="btnLoading" class="btn btn-primary" disabled style="display: none">

View File

@@ -44,10 +44,24 @@
</ul>
</li>
<li class="nav-item nav-item-has-subnav">
<a href="javascript:void(0)"><i class="mdi mdi-playlist-check"></i> <span>授权调用方</span></a>
<ul class="nav nav-subnav">
<li> <a class="multitabs" href="/authorized/list">调用方</a> </li>
</ul>
</li>
<li class="nav-item"> <a href="/swagger/index.html" target="_blank" ><i class="mdi mdi-file-document-box"></i> <span>接口文档</span></a> </li>
<li class="nav-item"> <a href="/graphql" target="_blank" ><i class="mdi mdi-file-document-box-search"></i> <span>GraphQL</span></a> </li>
<li class="nav-item"> <a href="/metrics" target="_blank" ><i class="mdi mdi-speedometer"></i> <span>接口指标</span></a> </li>
<li class="nav-item nav-item-has-subnav">
<a href="javascript:void(0)"><i class="mdi mdi-tools"></i> <span>工具箱</span></a>
<ul class="nav nav-subnav">
<li> <a class="multitabs" href="/tool/hashids">hashids</a> </li>
</ul>
</li>
</ul>
</nav>
</div>

View File

@@ -0,0 +1,153 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"/>
<link href="../../bootstrap/js/jquery-confirm/jquery-confirm.min.css" rel="stylesheet">
<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="../../bootstrap/css/materialdesignicons.min.css" rel="stylesheet">
<link href="../../bootstrap/css/style.min.css" rel="stylesheet">
</head>
<body>
<div class="container-fluid p-t-15">
<div class="row">
<div class="col-lg-6">
<div class="card">
<div class="card-header">
<div class="card-title">hashids 加密</div>
</div>
<div class="card-body">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">数字</span>
</div>
<input type="text" class="form-control" id="number" maxlength="10" placeholder="需加密的数字">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" >密文</span>
</div>
<input type="text" class="form-control" disabled id="NumberToEncodeValue">
</div>
<button type="button" id="btnEncode" class="btn btn-primary">执行</button>
<button type="button" id="btnEncodeLoading" class="btn btn-primary" disabled style="display: none">
<span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true"></span>
执行中...
</button>
</div>
</div>
</div>
<div class="col-lg-6">
<div class="card">
<header class="card-header">
<div class="card-title">hashids 解密</div>
</header>
<div class="card-body">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">密文</span>
</div>
<input type="text" class="form-control" id="encodeValue" placeholder="需解密的密文">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" >数字</span>
</div>
<input type="text" class="form-control" disabled id="DecodeValueToNumber">
</div>
<button type="button" id="btnDecode" class="btn btn-primary">执行</button>
<button type="button" id="btnDecodeLoading" class="btn btn-primary" disabled style="display: none">
<span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true"></span>
执行中...
</button>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="../../bootstrap/js/jquery.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/popper.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap-maxlength/bootstrap-maxlength.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="../../bootstrap/js/util.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$("input#number").maxlength({
warningClass: "badge badge-info",
limitReachedClass: "badge badge-warning"
});
$('#btnEncode').on('click', function () {
const number = $("#number").val();
if (number === "") {
$.alert({
title: '温馨提示',
icon: 'mdi mdi-alert',
type: 'orange',
content: '请输入需加密的数字。',
});
return false;
}
$(this).hide();
$("#btnEncodeLoading").show();
$.get("/api/tool/hashids/encode/" + number, "", function (data) {
$("#btnEncodeLoading").hide();
$("#btnEncode").show();
$("#NumberToEncodeValue").val(data.val)
}).fail(function (response) {
$("#btnEncodeLoading").hide();
$("#btnEncode").show();
AjaxError(response);
})
});
$('#btnDecode').on('click', function () {
const encodeValue = $("#encodeValue").val();
if (encodeValue === "") {
$.alert({
title: '温馨提示',
icon: 'mdi mdi-alert',
type: 'orange',
content: '请输入需解密的密文。',
});
return false;
}
$(this).hide();
$("#btnDecodeLoading").show();
$.get("/api/tool/hashids/decode/" + encodeValue, "", function (data) {
$("#btnDecodeLoading").hide();
$("#btnDecode").show();
$("#DecodeValueToNumber").val(data.val)
}).fail(function (response) {
$("#btnDecodeLoading").hide();
$("#btnDecode").show();
AjaxError(response);
})
});
})
</script>
</body>
</html>

View File

@@ -2,6 +2,7 @@ package main
import (
"flag"
"fmt"
"log"
"strings"
@@ -42,11 +43,34 @@ func main() {
}
}()
// 开启事务
tx := db.GetDb().Begin()
// 创建 user_demo 表
err = db.GetDb().Exec(mysql.CreateUserDemoTableSql()).Error
err = tx.Exec(mysql.CreateUserDemoTableSql()).Error
if err != nil {
tx.Rollback()
log.Fatal("create user_demo table err: ", err.Error())
}
fmt.Println("create user_demo table success")
// 创建 authorized 表
err = tx.Exec(mysql.CreateAuthorizedTableSql()).Error
if err != nil {
tx.Rollback()
log.Fatal("create authorized table err: ", err.Error())
}
fmt.Println("create authorized table success")
// 创建 authorized_api 表
err = tx.Exec(mysql.CreateAuthorizedAPITableSql()).Error
if err != nil {
tx.Rollback()
log.Fatal("create authorized_api table err: ", err.Error())
}
fmt.Println("create authorized_api table success")
// 完成事务
tx.Commit()
log.Println("create user_demo table success")
}

View File

@@ -0,0 +1,37 @@
package mysql
//CREATE TABLE `authorized` (
//`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
//`business_key` varchar(32) NOT NULL DEFAULT '' COMMENT '调用方key',
//`business_secret` varchar(60) NOT NULL DEFAULT '' COMMENT '调用方secret',
//`business_developer` varchar(60) NOT NULL DEFAULT '' COMMENT '调用方对接人',
//`remark` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
//`is_used` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否启用 1:是 -1:否',
//`is_deleted` tinyint(1) NOT NULL DEFAULT '-1' COMMENT '是否删除 1:是 -1:否',
//`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
//`created_user` varchar(60) NOT NULL DEFAULT '' COMMENT '创建人',
//`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
//`updated_user` varchar(60) NOT NULL DEFAULT '' COMMENT '更新人',
//PRIMARY KEY (`id`),
//UNIQUE KEY `unique_business_key` (`business_key`)
//) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='已授权的调用方表';
func CreateAuthorizedTableSql() (sql string) {
sql = "CREATE TABLE `authorized` ("
sql += "`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',"
sql += "`business_key` varchar(32) NOT NULL DEFAULT '' COMMENT '调用方key',"
sql += "`business_secret` varchar(60) NOT NULL DEFAULT '' COMMENT '调用方secret',"
sql += "`business_developer` varchar(60) NOT NULL DEFAULT '' COMMENT '调用方对接人',"
sql += "`remark` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',"
sql += "`is_used` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否启用 1:是 -1:否',"
sql += "`is_deleted` tinyint(1) NOT NULL DEFAULT '-1' COMMENT '是否删除 1:是 -1:否',"
sql += "`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',"
sql += "`created_user` varchar(60) NOT NULL DEFAULT '' COMMENT '创建人',"
sql += "`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',"
sql += "`updated_user` varchar(60) NOT NULL DEFAULT '' COMMENT '更新人',"
sql += "PRIMARY KEY (`id`),"
sql += "UNIQUE KEY `unique_business_key` (`business_key`)"
sql += ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='已授权的调用方表';"
return
}

View File

@@ -0,0 +1,31 @@
package mysql
//CREATE TABLE `authorized_api` (
//`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
//`business_key` varchar(30) NOT NULL DEFAULT '' COMMENT '调用方key',
//`method` varchar(30) NOT NULL DEFAULT '' COMMENT '请求方式',
//`api` varchar(100) NOT NULL DEFAULT '' COMMENT '请求地址',
//`is_deleted` tinyint(1) NOT NULL DEFAULT '-1' COMMENT '是否删除 1:是 -1:否',
//`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
//`created_user` varchar(60) NOT NULL DEFAULT '' COMMENT '创建人',
//`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
//`updated_user` varchar(60) NOT NULL DEFAULT '' COMMENT '更新人',
//PRIMARY KEY (`id`)
//) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='已授权接口地址';
func CreateAuthorizedAPITableSql() (sql string) {
sql = "CREATE TABLE `authorized_api` ("
sql += "`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',"
sql += "`business_key` varchar(30) NOT NULL DEFAULT '' COMMENT '调用方key',"
sql += "`method` varchar(30) NOT NULL DEFAULT '' COMMENT '请求方式',"
sql += "`api` varchar(100) NOT NULL DEFAULT '' COMMENT '请求地址',"
sql += "`is_deleted` tinyint(1) NOT NULL DEFAULT '-1' COMMENT '是否删除 1:是 -1:否',"
sql += "`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',"
sql += "`created_user` varchar(60) NOT NULL DEFAULT '' COMMENT '创建人',"
sql += "`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',"
sql += "`updated_user` varchar(60) NOT NULL DEFAULT '' COMMENT '更新人',"
sql += "PRIMARY KEY (`id`)"
sql += ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='已授权的调用方表';"
return
}

195
cmd/mfmt/main.go Normal file
View File

@@ -0,0 +1,195 @@
package main
import (
"bufio"
"bytes"
"crypto/sha256"
"fmt"
"go/ast"
"go/format"
"go/parser"
"go/token"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"github.com/koketama/errors"
"go.uber.org/zap"
"golang.org/x/tools/go/packages"
)
var stdlib = make(map[string]bool)
func init() {
pkgs, err := packages.Load(nil, "std")
if err != nil {
log.Fatal("get go stdlib err", zap.Error(err))
}
for _, pkg := range pkgs {
if !strings.HasPrefix(pkg.ID, "vendor") {
stdlib[pkg.ID] = true
}
}
}
var module string
func init() {
file, err := os.Open("./go.mod")
if err != nil {
log.Fatal("no go.mod file found", zap.Error(err))
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if strings.HasPrefix(line, "module ") {
module = strings.TrimSpace(line[7:])
break
}
}
if module == "" {
log.Fatal("go.mod illegal")
}
}
func main() {
err := filepath.Walk("./", func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() || strings.HasPrefix(path, ".") || strings.HasPrefix(path, "vendor") || strings.HasSuffix(path, ".pb.go") || filepath.Ext(path) != ".go" {
return nil
}
raw, err := ioutil.ReadFile(path)
if err != nil {
return errors.Wrapf(err, "read file %s err", path)
}
digest0 := sha256.Sum256(raw)
if raw, err = format.Source(raw); err != nil {
return errors.Wrapf(err, "format file %s err", path)
}
file, err := parser.ParseFile(token.NewFileSet(), "", raw, 0)
if err != nil {
return errors.Wrapf(err, "parse file %s err", path)
}
var first, last int
var imports []*ast.ImportSpec
comments := make(map[string]string)
ast.Inspect(file, func(n ast.Node) bool {
switch spec := n.(type) {
case *ast.ImportSpec:
if first == 0 {
first = int(spec.Pos())
}
last = int(spec.End())
imports = append(imports, spec)
k := last - 1
for ; k < len(raw); k++ {
if raw[k] == '\r' || raw[k] == '\n' {
break
}
}
comment := string(raw[last-1 : k])
if index := strings.Index(comment, "//"); index != -1 {
comments[spec.Path.Value] = strings.TrimSpace(comment[index+2:])
}
}
return true
})
if imports != nil {
buf := bytes.NewBuffer(nil)
buf.Write(raw[:first-2])
buf.WriteString(sort(imports, comments))
buf.Write(raw[last-1:])
if raw, err = format.Source(buf.Bytes()); err != nil {
return errors.Wrapf(err, "double format file %s err", path)
}
}
digest1 := sha256.Sum256(raw)
if !bytes.Equal(digest0[:], digest1[:]) {
fmt.Println(path)
}
if err = ioutil.WriteFile(path, raw, info.Mode()); err != nil {
return errors.Wrapf(err, "write file %s err", path)
}
return nil
})
if err != nil {
log.Fatal("scan project err", zap.Error(err))
}
}
func sort(imports []*ast.ImportSpec, comments map[string]string) string {
system := bytes.NewBuffer(nil)
group := bytes.NewBuffer(nil)
others := bytes.NewBuffer(nil)
for _, pkg := range imports {
value := strings.Trim(pkg.Path.Value, `"`)
switch {
case stdlib[value]:
if pkg.Name != nil {
system.WriteString(pkg.Name.String())
system.WriteString(" ")
}
system.WriteString(pkg.Path.Value)
if comment, ok := comments[pkg.Path.Value]; ok {
system.WriteString(" ")
system.WriteString("// ")
system.WriteString(comment)
}
system.WriteString("\n")
case strings.HasPrefix(value, module):
if pkg.Name != nil {
group.WriteString(pkg.Name.String())
group.WriteString(" ")
}
group.WriteString(pkg.Path.Value)
if comment, ok := comments[pkg.Path.Value]; ok {
group.WriteString(" ")
group.WriteString("// ")
group.WriteString(comment)
}
group.WriteString("\n")
default:
if pkg.Name != nil {
others.WriteString(pkg.Name.String())
others.WriteString(" ")
}
others.WriteString(pkg.Path.Value)
if comment, ok := comments[pkg.Path.Value]; ok {
others.WriteString(" ")
others.WriteString("// ")
others.WriteString(comment)
}
others.WriteString("\n")
}
}
return fmt.Sprintf("%s\n%s\n%s", system.String(), group.String(), others.String())
}

View File

@@ -58,6 +58,11 @@ type Config struct {
Secret string `toml:"secret"`
ExpireDuration time.Duration `toml:"expireDuration"`
} `toml:"urlToken"`
HashIds struct {
Secret string `toml:"secret"`
Length int `toml:"length"`
} `toml:"hashids"`
}
func init() {

View File

@@ -37,3 +37,7 @@ expireDuration = 24 # JWT ExpiresAt 过期时间(单位:小时)
[urlToken]
secret = 'i1ydX9RtHyuJTrw7frcu' # URL Token secret
expireDuration = 10 # URL Token ExpiresAt 过期时间(单位:分钟)
[hashids]
secret = '6ab6122836cfef95f8db' # hashids secret
length = 12 # hashids length

View File

@@ -28,6 +28,378 @@ var doc = `{
"host": "{{.Host}}",
"basePath": "{{.BasePath}}",
"paths": {
"/api/authorized": {
"get": {
"description": "调用方列表",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.authorized"
],
"summary": "调用方列表",
"parameters": [
{
"type": "integer",
"description": "第几页",
"name": "page",
"in": "query"
},
{
"type": "string",
"description": "每页显示条数",
"name": "page_size",
"in": "query"
},
{
"type": "string",
"description": "调用方key",
"name": "business_key",
"in": "query"
},
{
"type": "string",
"description": "调用方secret",
"name": "business_secret",
"in": "query"
},
{
"type": "string",
"description": "调用方对接人",
"name": "business_developer",
"in": "query"
},
{
"type": "string",
"description": "备注",
"name": "remark",
"in": "path"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/authorized_handler.listResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
},
"post": {
"description": "新增调用方",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.authorized"
],
"summary": "新增调用方",
"parameters": [
{
"description": "请求信息",
"name": "Request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/authorized_handler.createRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/authorized_handler.createResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/api/authorized/used": {
"patch": {
"description": "更新调用方为启用/禁用",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.authorized"
],
"summary": "更新调用方为启用/禁用",
"parameters": [
{
"description": "请求信息",
"name": "Request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/authorized_handler.updateUsedRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/authorized_handler.updateUsedResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/api/authorized/{id}": {
"delete": {
"description": "删除调用方",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.authorized"
],
"summary": "删除调用方",
"parameters": [
{
"type": "string",
"description": "hashId",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/authorized_handler.deleteResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/api/authorized_api": {
"get": {
"description": "调用方接口地址列表",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.authorized"
],
"summary": "调用方接口地址列表",
"parameters": [
{
"type": "string",
"description": "调用方key",
"name": "business_key",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/authorized_handler.listAPIResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
},
"post": {
"description": "授权调用方接口地址",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.authorized"
],
"summary": "授权调用方接口地址",
"parameters": [
{
"description": "请求信息",
"name": "Request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/authorized_handler.createAPIRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/authorized_handler.createAPIResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/api/authorized_api/{id}": {
"delete": {
"description": "删除调用方接口地址",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.authorized"
],
"summary": "删除调用方接口地址",
"parameters": [
{
"type": "integer",
"description": "主键ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/authorized_handler.deleteAPIResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/api/tool/hashids/decode/{id}": {
"get": {
"description": "HashIds 解密",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.tool"
],
"summary": "HashIds 解密",
"parameters": [
{
"type": "string",
"description": "需解密的密文",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/tool_handler.hashIdsDecodeResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/api/tool/hashids/encode/{id}": {
"get": {
"description": "HashIds 加密",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.tool"
],
"summary": "HashIds 加密",
"parameters": [
{
"type": "string",
"description": "需加密的数字",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/tool_handler.hashIdsEncodeResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/auth/get": {
"post": {
"description": "获取授权信息",
@@ -114,6 +486,166 @@ var doc = `{
}
}
},
"/test/create": {
"post": {
"description": "创建用户",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Test"
],
"summary": "创建用户",
"parameters": [
{
"description": "请求信息",
"name": "Request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/test_handler.createRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/test_handler.createResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/test/delete": {
"post": {
"description": "删除用户",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Test"
],
"summary": "删除用户",
"parameters": [
{
"description": "请求信息",
"name": "Request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/test_handler.deleteRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/test_handler.deleteResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/test/detail": {
"post": {
"description": "用户详情",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Test"
],
"summary": "用户详情",
"parameters": [
{
"description": "请求信息",
"name": "Request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/test_handler.detailRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/test_handler.detailResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/test/update": {
"post": {
"description": "编辑用户",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Test"
],
"summary": "编辑用户",
"parameters": [
{
"description": "请求信息",
"name": "Request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/test_handler.updateRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/test_handler.updateResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/user/create": {
"post": {
"description": "创建用户",
@@ -324,6 +856,204 @@ var doc = `{
}
},
"definitions": {
"authorized_handler.createAPIRequest": {
"type": "object",
"properties": {
"api": {
"description": "请求地址",
"type": "string"
},
"id": {
"description": "HashID",
"type": "string"
},
"method": {
"description": "请求方法",
"type": "string"
}
}
},
"authorized_handler.createAPIResponse": {
"type": "object",
"properties": {
"id": {
"description": "主键ID",
"type": "integer"
}
}
},
"authorized_handler.createRequest": {
"type": "object",
"properties": {
"business_developer": {
"description": "调用方对接人",
"type": "string"
},
"business_key": {
"description": "调用方key",
"type": "string"
},
"remark": {
"description": "备注",
"type": "string"
}
}
},
"authorized_handler.createResponse": {
"type": "object",
"properties": {
"id": {
"description": "主键ID",
"type": "integer"
}
}
},
"authorized_handler.deleteAPIResponse": {
"type": "object",
"properties": {
"id": {
"description": "主键ID",
"type": "integer"
}
}
},
"authorized_handler.deleteResponse": {
"type": "object",
"properties": {
"id": {
"description": "主键ID",
"type": "integer"
}
}
},
"authorized_handler.listAPIData": {
"type": "object",
"properties": {
"api": {
"description": "调用方对接人",
"type": "string"
},
"business_key": {
"description": "调用方key",
"type": "string"
},
"hash_id": {
"description": "hashID",
"type": "string"
},
"method": {
"description": "调用方secret",
"type": "string"
}
}
},
"authorized_handler.listAPIResponse": {
"type": "object",
"properties": {
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/authorized_handler.listAPIData"
}
}
}
},
"authorized_handler.listData": {
"type": "object",
"properties": {
"business_developer": {
"description": "调用方对接人",
"type": "string"
},
"business_key": {
"description": "调用方key",
"type": "string"
},
"business_secret": {
"description": "调用方secret",
"type": "string"
},
"created_at": {
"description": "创建时间",
"type": "string"
},
"created_user": {
"description": "创建人",
"type": "string"
},
"hashid": {
"description": "hashid",
"type": "string"
},
"id": {
"description": "ID",
"type": "integer"
},
"is_used": {
"description": "是否启用 1:是 -1:否",
"type": "integer"
},
"remark": {
"description": "备注",
"type": "string"
},
"updated_at": {
"description": "更新时间",
"type": "string"
},
"updated_user": {
"description": "更新人",
"type": "string"
}
}
},
"authorized_handler.listResponse": {
"type": "object",
"properties": {
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/authorized_handler.listData"
}
},
"pagination": {
"type": "object",
"properties": {
"current_page": {
"type": "integer"
},
"pre_page_count": {
"type": "integer"
},
"total": {
"type": "integer"
}
}
}
}
},
"authorized_handler.updateUsedRequest": {
"type": "object",
"properties": {
"id": {
"description": "主键ID",
"type": "string"
},
"used": {
"description": "是否启用 1:是 -1:否",
"type": "integer"
}
}
},
"authorized_handler.updateUsedResponse": {
"type": "object",
"properties": {
"id": {
"description": "主键ID",
"type": "integer"
}
}
},
"code.Failure": {
"type": "object",
"properties": {
@@ -350,6 +1080,48 @@ var doc = `{
}
}
},
"test_handler.createRequest": {
"type": "object"
},
"test_handler.createResponse": {
"type": "object"
},
"test_handler.deleteRequest": {
"type": "object"
},
"test_handler.deleteResponse": {
"type": "object"
},
"test_handler.detailRequest": {
"type": "object"
},
"test_handler.detailResponse": {
"type": "object"
},
"test_handler.updateRequest": {
"type": "object"
},
"test_handler.updateResponse": {
"type": "object"
},
"tool_handler.hashIdsDecodeResponse": {
"type": "object",
"properties": {
"val": {
"description": "解密后的值",
"type": "integer"
}
}
},
"tool_handler.hashIdsEncodeResponse": {
"type": "object",
"properties": {
"val": {
"description": "加密后的值",
"type": "string"
}
}
},
"user_handler.createRequest": {
"type": "object",
"properties": {

View File

@@ -11,6 +11,378 @@
},
"host": "127.0.0.1:9999",
"paths": {
"/api/authorized": {
"get": {
"description": "调用方列表",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.authorized"
],
"summary": "调用方列表",
"parameters": [
{
"type": "integer",
"description": "第几页",
"name": "page",
"in": "query"
},
{
"type": "string",
"description": "每页显示条数",
"name": "page_size",
"in": "query"
},
{
"type": "string",
"description": "调用方key",
"name": "business_key",
"in": "query"
},
{
"type": "string",
"description": "调用方secret",
"name": "business_secret",
"in": "query"
},
{
"type": "string",
"description": "调用方对接人",
"name": "business_developer",
"in": "query"
},
{
"type": "string",
"description": "备注",
"name": "remark",
"in": "path"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/authorized_handler.listResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
},
"post": {
"description": "新增调用方",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.authorized"
],
"summary": "新增调用方",
"parameters": [
{
"description": "请求信息",
"name": "Request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/authorized_handler.createRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/authorized_handler.createResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/api/authorized/used": {
"patch": {
"description": "更新调用方为启用/禁用",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.authorized"
],
"summary": "更新调用方为启用/禁用",
"parameters": [
{
"description": "请求信息",
"name": "Request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/authorized_handler.updateUsedRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/authorized_handler.updateUsedResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/api/authorized/{id}": {
"delete": {
"description": "删除调用方",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.authorized"
],
"summary": "删除调用方",
"parameters": [
{
"type": "string",
"description": "hashId",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/authorized_handler.deleteResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/api/authorized_api": {
"get": {
"description": "调用方接口地址列表",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.authorized"
],
"summary": "调用方接口地址列表",
"parameters": [
{
"type": "string",
"description": "调用方key",
"name": "business_key",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/authorized_handler.listAPIResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
},
"post": {
"description": "授权调用方接口地址",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.authorized"
],
"summary": "授权调用方接口地址",
"parameters": [
{
"description": "请求信息",
"name": "Request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/authorized_handler.createAPIRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/authorized_handler.createAPIResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/api/authorized_api/{id}": {
"delete": {
"description": "删除调用方接口地址",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.authorized"
],
"summary": "删除调用方接口地址",
"parameters": [
{
"type": "integer",
"description": "主键ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/authorized_handler.deleteAPIResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/api/tool/hashids/decode/{id}": {
"get": {
"description": "HashIds 解密",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.tool"
],
"summary": "HashIds 解密",
"parameters": [
{
"type": "string",
"description": "需解密的密文",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/tool_handler.hashIdsDecodeResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/api/tool/hashids/encode/{id}": {
"get": {
"description": "HashIds 加密",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"API.tool"
],
"summary": "HashIds 加密",
"parameters": [
{
"type": "string",
"description": "需加密的数字",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/tool_handler.hashIdsEncodeResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/auth/get": {
"post": {
"description": "获取授权信息",
@@ -97,6 +469,166 @@
}
}
},
"/test/create": {
"post": {
"description": "创建用户",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Test"
],
"summary": "创建用户",
"parameters": [
{
"description": "请求信息",
"name": "Request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/test_handler.createRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/test_handler.createResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/test/delete": {
"post": {
"description": "删除用户",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Test"
],
"summary": "删除用户",
"parameters": [
{
"description": "请求信息",
"name": "Request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/test_handler.deleteRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/test_handler.deleteResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/test/detail": {
"post": {
"description": "用户详情",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Test"
],
"summary": "用户详情",
"parameters": [
{
"description": "请求信息",
"name": "Request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/test_handler.detailRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/test_handler.detailResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/test/update": {
"post": {
"description": "编辑用户",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Test"
],
"summary": "编辑用户",
"parameters": [
{
"description": "请求信息",
"name": "Request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/test_handler.updateRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/test_handler.updateResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/code.Failure"
}
}
}
}
},
"/user/create": {
"post": {
"description": "创建用户",
@@ -307,6 +839,204 @@
}
},
"definitions": {
"authorized_handler.createAPIRequest": {
"type": "object",
"properties": {
"api": {
"description": "请求地址",
"type": "string"
},
"id": {
"description": "HashID",
"type": "string"
},
"method": {
"description": "请求方法",
"type": "string"
}
}
},
"authorized_handler.createAPIResponse": {
"type": "object",
"properties": {
"id": {
"description": "主键ID",
"type": "integer"
}
}
},
"authorized_handler.createRequest": {
"type": "object",
"properties": {
"business_developer": {
"description": "调用方对接人",
"type": "string"
},
"business_key": {
"description": "调用方key",
"type": "string"
},
"remark": {
"description": "备注",
"type": "string"
}
}
},
"authorized_handler.createResponse": {
"type": "object",
"properties": {
"id": {
"description": "主键ID",
"type": "integer"
}
}
},
"authorized_handler.deleteAPIResponse": {
"type": "object",
"properties": {
"id": {
"description": "主键ID",
"type": "integer"
}
}
},
"authorized_handler.deleteResponse": {
"type": "object",
"properties": {
"id": {
"description": "主键ID",
"type": "integer"
}
}
},
"authorized_handler.listAPIData": {
"type": "object",
"properties": {
"api": {
"description": "调用方对接人",
"type": "string"
},
"business_key": {
"description": "调用方key",
"type": "string"
},
"hash_id": {
"description": "hashID",
"type": "string"
},
"method": {
"description": "调用方secret",
"type": "string"
}
}
},
"authorized_handler.listAPIResponse": {
"type": "object",
"properties": {
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/authorized_handler.listAPIData"
}
}
}
},
"authorized_handler.listData": {
"type": "object",
"properties": {
"business_developer": {
"description": "调用方对接人",
"type": "string"
},
"business_key": {
"description": "调用方key",
"type": "string"
},
"business_secret": {
"description": "调用方secret",
"type": "string"
},
"created_at": {
"description": "创建时间",
"type": "string"
},
"created_user": {
"description": "创建人",
"type": "string"
},
"hashid": {
"description": "hashid",
"type": "string"
},
"id": {
"description": "ID",
"type": "integer"
},
"is_used": {
"description": "是否启用 1:是 -1:否",
"type": "integer"
},
"remark": {
"description": "备注",
"type": "string"
},
"updated_at": {
"description": "更新时间",
"type": "string"
},
"updated_user": {
"description": "更新人",
"type": "string"
}
}
},
"authorized_handler.listResponse": {
"type": "object",
"properties": {
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/authorized_handler.listData"
}
},
"pagination": {
"type": "object",
"properties": {
"current_page": {
"type": "integer"
},
"pre_page_count": {
"type": "integer"
},
"total": {
"type": "integer"
}
}
}
}
},
"authorized_handler.updateUsedRequest": {
"type": "object",
"properties": {
"id": {
"description": "主键ID",
"type": "string"
},
"used": {
"description": "是否启用 1:是 -1:否",
"type": "integer"
}
}
},
"authorized_handler.updateUsedResponse": {
"type": "object",
"properties": {
"id": {
"description": "主键ID",
"type": "integer"
}
}
},
"code.Failure": {
"type": "object",
"properties": {
@@ -333,6 +1063,48 @@
}
}
},
"test_handler.createRequest": {
"type": "object"
},
"test_handler.createResponse": {
"type": "object"
},
"test_handler.deleteRequest": {
"type": "object"
},
"test_handler.deleteResponse": {
"type": "object"
},
"test_handler.detailRequest": {
"type": "object"
},
"test_handler.detailResponse": {
"type": "object"
},
"test_handler.updateRequest": {
"type": "object"
},
"test_handler.updateResponse": {
"type": "object"
},
"tool_handler.hashIdsDecodeResponse": {
"type": "object",
"properties": {
"val": {
"description": "解密后的值",
"type": "integer"
}
}
},
"tool_handler.hashIdsEncodeResponse": {
"type": "object",
"properties": {
"val": {
"description": "加密后的值",
"type": "string"
}
}
},
"user_handler.createRequest": {
"type": "object",
"properties": {

View File

@@ -1,4 +1,141 @@
definitions:
authorized_handler.createAPIRequest:
properties:
api:
description: 请求地址
type: string
id:
description: HashID
type: string
method:
description: 请求方法
type: string
type: object
authorized_handler.createAPIResponse:
properties:
id:
description: 主键ID
type: integer
type: object
authorized_handler.createRequest:
properties:
business_developer:
description: 调用方对接人
type: string
business_key:
description: 调用方key
type: string
remark:
description: 备注
type: string
type: object
authorized_handler.createResponse:
properties:
id:
description: 主键ID
type: integer
type: object
authorized_handler.deleteAPIResponse:
properties:
id:
description: 主键ID
type: integer
type: object
authorized_handler.deleteResponse:
properties:
id:
description: 主键ID
type: integer
type: object
authorized_handler.listAPIData:
properties:
api:
description: 调用方对接人
type: string
business_key:
description: 调用方key
type: string
hash_id:
description: hashID
type: string
method:
description: 调用方secret
type: string
type: object
authorized_handler.listAPIResponse:
properties:
list:
items:
$ref: '#/definitions/authorized_handler.listAPIData'
type: array
type: object
authorized_handler.listData:
properties:
business_developer:
description: 调用方对接人
type: string
business_key:
description: 调用方key
type: string
business_secret:
description: 调用方secret
type: string
created_at:
description: 创建时间
type: string
created_user:
description: 创建人
type: string
hashid:
description: hashid
type: string
id:
description: ID
type: integer
is_used:
description: 是否启用 1:是 -1:否
type: integer
remark:
description: 备注
type: string
updated_at:
description: 更新时间
type: string
updated_user:
description: 更新人
type: string
type: object
authorized_handler.listResponse:
properties:
list:
items:
$ref: '#/definitions/authorized_handler.listData'
type: array
pagination:
properties:
current_page:
type: integer
pre_page_count:
type: integer
total:
type: integer
type: object
type: object
authorized_handler.updateUsedRequest:
properties:
id:
description: 主键ID
type: string
used:
description: 是否启用 1:是 -1:否
type: integer
type: object
authorized_handler.updateUsedResponse:
properties:
id:
description: 主键ID
type: integer
type: object
code.Failure:
properties:
code:
@@ -17,6 +154,34 @@ definitions:
description: 过期时间
type: integer
type: object
test_handler.createRequest:
type: object
test_handler.createResponse:
type: object
test_handler.deleteRequest:
type: object
test_handler.deleteResponse:
type: object
test_handler.detailRequest:
type: object
test_handler.detailResponse:
type: object
test_handler.updateRequest:
type: object
test_handler.updateResponse:
type: object
tool_handler.hashIdsDecodeResponse:
properties:
val:
description: 解密后的值
type: integer
type: object
tool_handler.hashIdsEncodeResponse:
properties:
val:
description: 加密后的值
type: string
type: object
user_handler.createRequest:
properties:
mobile:
@@ -80,6 +245,250 @@ info:
title: swagger 接口文档
version: "2.0"
paths:
/api/authorized:
get:
consumes:
- application/json
description: 调用方列表
parameters:
- description: 第几页
in: query
name: page
type: integer
- description: 每页显示条数
in: query
name: page_size
type: string
- description: 调用方key
in: query
name: business_key
type: string
- description: 调用方secret
in: query
name: business_secret
type: string
- description: 调用方对接人
in: query
name: business_developer
type: string
- description: 备注
in: path
name: remark
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/authorized_handler.listResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/code.Failure'
summary: 调用方列表
tags:
- API.authorized
post:
consumes:
- application/json
description: 新增调用方
parameters:
- description: 请求信息
in: body
name: Request
required: true
schema:
$ref: '#/definitions/authorized_handler.createRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/authorized_handler.createResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/code.Failure'
summary: 新增调用方
tags:
- API.authorized
/api/authorized/{id}:
delete:
consumes:
- application/json
description: 删除调用方
parameters:
- description: hashId
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/authorized_handler.deleteResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/code.Failure'
summary: 删除调用方
tags:
- API.authorized
/api/authorized/used:
patch:
consumes:
- application/json
description: 更新调用方为启用/禁用
parameters:
- description: 请求信息
in: body
name: Request
required: true
schema:
$ref: '#/definitions/authorized_handler.updateUsedRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/authorized_handler.updateUsedResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/code.Failure'
summary: 更新调用方为启用/禁用
tags:
- API.authorized
/api/authorized_api:
get:
consumes:
- application/json
description: 调用方接口地址列表
parameters:
- description: 调用方key
in: query
name: business_key
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/authorized_handler.listAPIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/code.Failure'
summary: 调用方接口地址列表
tags:
- API.authorized
post:
consumes:
- application/json
description: 授权调用方接口地址
parameters:
- description: 请求信息
in: body
name: Request
required: true
schema:
$ref: '#/definitions/authorized_handler.createAPIRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/authorized_handler.createAPIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/code.Failure'
summary: 授权调用方接口地址
tags:
- API.authorized
/api/authorized_api/{id}:
delete:
consumes:
- application/json
description: 删除调用方接口地址
parameters:
- description: 主键ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/authorized_handler.deleteAPIResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/code.Failure'
summary: 删除调用方接口地址
tags:
- API.authorized
/api/tool/hashids/decode/{id}:
get:
consumes:
- application/json
description: HashIds 解密
parameters:
- description: 需解密的密文
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/tool_handler.hashIdsDecodeResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/code.Failure'
summary: HashIds 解密
tags:
- API.tool
/api/tool/hashids/encode/{id}:
get:
consumes:
- application/json
description: HashIds 加密
parameters:
- description: 需加密的数字
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/tool_handler.hashIdsEncodeResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/code.Failure'
summary: HashIds 加密
tags:
- API.tool
/auth/get:
post:
consumes:
@@ -137,6 +546,110 @@ paths:
summary: Trace 示例
tags:
- Demo
/test/create:
post:
consumes:
- application/json
description: 创建用户
parameters:
- description: 请求信息
in: body
name: Request
required: true
schema:
$ref: '#/definitions/test_handler.createRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/test_handler.createResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/code.Failure'
summary: 创建用户
tags:
- Test
/test/delete:
post:
consumes:
- application/json
description: 删除用户
parameters:
- description: 请求信息
in: body
name: Request
required: true
schema:
$ref: '#/definitions/test_handler.deleteRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/test_handler.deleteResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/code.Failure'
summary: 删除用户
tags:
- Test
/test/detail:
post:
consumes:
- application/json
description: 用户详情
parameters:
- description: 请求信息
in: body
name: Request
required: true
schema:
$ref: '#/definitions/test_handler.detailRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/test_handler.detailResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/code.Failure'
summary: 用户详情
tags:
- Test
/test/update:
post:
consumes:
- application/json
description: 编辑用户
parameters:
- description: 请求信息
in: body
name: Request
required: true
schema:
$ref: '#/definitions/test_handler.updateRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/test_handler.updateResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/code.Failure'
summary: 编辑用户
tags:
- Test
/user/create:
post:
consumes:

1
go.mod
View File

@@ -23,6 +23,7 @@ require (
github.com/prometheus/client_golang v0.9.3
github.com/rs/cors v1.7.0
github.com/shirou/gopsutil v3.21.2+incompatible
github.com/speps/go-hashids v2.0.0+incompatible
github.com/spf13/cast v1.3.0
github.com/spf13/viper v1.7.1
github.com/swaggo/gin-swagger v1.3.0

2
go.sum
View File

@@ -351,6 +351,8 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/speps/go-hashids v2.0.0+incompatible h1:kSfxGfESueJKTx0mpER9Y/1XHl+FVQjtCqRyYcviFbw=
github.com/speps/go-hashids v2.0.0+incompatible/go.mod h1:P7hqPzMdnZOfyIk+xrlG1QaSMw+gCBdHKsBDnhpaZvc=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=

View File

@@ -15,6 +15,7 @@ const (
CallHTTPError = 10105
ResubmitError = 10106
ResubmitMsg = 10107
HashIdsDecodeError = 10108
// 模块级错误码 - 用户模块
IllegalUserName = 20101
@@ -22,7 +23,15 @@ const (
UserUpdateError = 20103
UserSearchError = 20104
// ...
// 授权调用方
AuthorizedCreateError = 30101
AuthorizedListError = 30102
AuthorizedDeleteError = 30103
AuthorizedUpdateError = 30104
AuthorizedDetailError = 30105
AuthorizedCreateAPIError = 30106
AuthorizedListAPIError = 30107
AuthorizedDeleteAPIError = 30108
)
var codeText = map[int]string{
@@ -33,11 +42,21 @@ var codeText = map[int]string{
CallHTTPError: "调用第三方 HTTP 接口失败",
ResubmitError: "Resubmit Error",
ResubmitMsg: "请勿重复提交",
HashIdsDecodeError: "ID 参数有误",
IllegalUserName: "非法用户名",
UserCreateError: "创建用户失败",
UserUpdateError: "更新用户失败",
UserSearchError: "查询用户失败",
AuthorizedCreateError: "创建调用方失败",
AuthorizedListError: "获取调用方列表页失败",
AuthorizedDeleteError: "删除调用方失败",
AuthorizedUpdateError: "更新调用方失败",
AuthorizedDetailError: "获取调用方详情失败",
AuthorizedCreateAPIError: "创建调用方API地址失败",
AuthorizedListAPIError: "获取调用方API地址列表失败",
AuthorizedDeleteAPIError: "删除调用方API地址失败",
}
func Text(code int) string {

View File

@@ -0,0 +1,63 @@
package authorized_handler
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/code"
"github.com/xinliangnote/go-gin-api/internal/api/service/authorized_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type createRequest struct {
BusinessKey string `json:"business_key"` // 调用方key
BusinessDeveloper string `json:"business_developer"` // 调用方对接人
Remark string `json:"remark"` // 备注
}
type createResponse struct {
Id int32 `json:"id"` // 主键ID
}
// Create 新增调用方
// @Summary 新增调用方
// @Description 新增调用方
// @Tags API.authorized
// @Accept json
// @Produce json
// @Param Request body createRequest true "请求信息"
// @Success 200 {object} createResponse
// @Failure 400 {object} code.Failure
// @Router /api/authorized [post]
func (h *handler) Create() core.HandlerFunc {
return func(c core.Context) {
req := new(createRequest)
res := new(createResponse)
if err := c.ShouldBindJSON(req); err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
)
return
}
createData := new(authorized_service.CreateAuthorizedData)
createData.BusinessKey = req.BusinessKey
createData.BusinessDeveloper = req.BusinessDeveloper
createData.Remark = req.Remark
id, err := h.authorizedService.Create(c, createData)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.AuthorizedCreateError,
code.Text(code.AuthorizedCreateError)).WithErr(err),
)
return
}
res.Id = id
c.Payload(res)
}
}

View File

@@ -0,0 +1,86 @@
package authorized_handler
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/code"
"github.com/xinliangnote/go-gin-api/internal/api/service/authorized_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type createAPIRequest struct {
Id string `json:"id"` // HashID
Method string `json:"method"` // 请求方法
API string `json:"api"` // 请求地址
}
type createAPIResponse struct {
Id int32 `json:"id"` // 主键ID
}
// CreateAPI 授权调用方接口地址
// @Summary 授权调用方接口地址
// @Description 授权调用方接口地址
// @Tags API.authorized
// @Accept json
// @Produce json
// @Param Request body createAPIRequest true "请求信息"
// @Success 200 {object} createAPIResponse
// @Failure 400 {object} code.Failure
// @Router /api/authorized_api [post]
func (h *handler) CreateAPI() core.HandlerFunc {
return func(c core.Context) {
req := new(createAPIRequest)
res := new(createAPIResponse)
if err := c.ShouldBindJSON(req); err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
)
return
}
id := int32(ids[0])
// 通过 id 查询出 business_key
authorizedInfo, err := h.authorizedService.Detail(c, id)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.AuthorizedDetailError,
code.Text(code.AuthorizedDetailError)).WithErr(err),
)
return
}
createAPIData := new(authorized_service.CreateAuthorizedAPIData)
createAPIData.BusinessKey = authorizedInfo.BusinessKey
createAPIData.Method = req.Method
createAPIData.API = req.API
createId, err := h.authorizedService.CreateAPI(c, createAPIData)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.AuthorizedCreateAPIError,
code.Text(code.AuthorizedCreateAPIError)).WithErr(err),
)
return
}
res.Id = createId
c.Payload(res)
}
}

View File

@@ -0,0 +1,67 @@
package authorized_handler
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type deleteRequest struct {
Id string `uri:"id"` // HashID
}
type deleteResponse struct {
Id int32 `json:"id"` // 主键ID
}
// Delete 删除调用方
// @Summary 删除调用方
// @Description 删除调用方
// @Tags API.authorized
// @Accept json
// @Produce json
// @Param id path string true "hashId"
// @Success 200 {object} deleteResponse
// @Failure 400 {object} code.Failure
// @Router /api/authorized/{id} [delete]
func (h *handler) Delete() core.HandlerFunc {
return func(c core.Context) {
req := new(deleteRequest)
res := new(deleteResponse)
if err := c.ShouldBindURI(req); err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
)
return
}
id := int32(ids[0])
err = h.authorizedService.Delete(c, id)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.AuthorizedDeleteError,
code.Text(code.AuthorizedDeleteError)).WithErr(err),
)
return
}
res.Id = id
c.Payload(res)
}
}

View File

@@ -0,0 +1,67 @@
package authorized_handler
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type deleteAPIRequest struct {
Id string `uri:"id"` // HashID
}
type deleteAPIResponse struct {
Id int32 `json:"id"` // 主键ID
}
// DeleteAPI 删除调用方接口地址
// @Summary 删除调用方接口地址
// @Description 删除调用方接口地址
// @Tags API.authorized
// @Accept json
// @Produce json
// @Param id path int true "主键ID"
// @Success 200 {object} deleteAPIResponse
// @Failure 400 {object} code.Failure
// @Router /api/authorized_api/{id} [delete]
func (h *handler) DeleteAPI() core.HandlerFunc {
return func(c core.Context) {
req := new(deleteAPIRequest)
res := new(deleteAPIResponse)
if err := c.ShouldBindURI(req); err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
)
return
}
id := int32(ids[0])
err = h.authorizedService.DeleteAPI(c, id)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.AuthorizedDeleteAPIError,
code.Text(code.AuthorizedDeleteAPIError)).WithErr(err),
)
return
}
res.Id = id
c.Payload(res)
}
}

View File

@@ -0,0 +1,142 @@
package authorized_handler
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/code"
"github.com/xinliangnote/go-gin-api/internal/api/service/authorized_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/xinliangnote/go-gin-api/pkg/time_parse"
"github.com/spf13/cast"
"go.uber.org/zap"
)
type listRequest struct {
Page int `form:"page"` // 第几页
PageSize int `form:"page_size"` // 每页显示条数
BusinessKey string `form:"business_key"` // 调用方key
BusinessSecret string `form:"business_secret"` // 调用方secret
BusinessDeveloper string `form:"business_developer"` // 调用方对接人
Remark string `form:"remark"` // 备注
}
type listData struct {
Id int `json:"id"` // ID
HashID string `json:"hashid"` // hashid
BusinessKey string `json:"business_key"` // 调用方key
BusinessSecret string `json:"business_secret"` // 调用方secret
BusinessDeveloper string `json:"business_developer"` // 调用方对接人
Remark string `json:"remark"` // 备注
IsUsed int `json:"is_used"` // 是否启用 1:是 -1:否
CreatedAt string `json:"created_at"` // 创建时间
CreatedUser string `json:"created_user"` // 创建人
UpdatedAt string `json:"updated_at"` // 更新时间
UpdatedUser string `json:"updated_user"` // 更新人
}
type listResponse struct {
List []listData `json:"list"`
Pagination struct {
Total int `json:"total"`
CurrentPage int `json:"current_page"`
PrePageCount int `json:"pre_page_count"`
} `json:"pagination"`
}
// List 调用方列表
// @Summary 调用方列表
// @Description 调用方列表
// @Tags API.authorized
// @Accept json
// @Produce json
// @Param page query int false "第几页"
// @Param page_size query string false "每页显示条数"
// @Param business_key query string false "调用方key"
// @Param business_secret query string false "调用方secret"
// @Param business_developer query string false "调用方对接人"
// @Param remark path string false "备注"
// @Success 200 {object} listResponse
// @Failure 400 {object} code.Failure
// @Router /api/authorized [get]
func (h *handler) List() core.HandlerFunc {
return func(c core.Context) {
req := new(listRequest)
res := new(listResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
)
return
}
page := req.Page
if page == 0 {
page = 1
}
pageSize := req.PageSize
if pageSize == 0 {
pageSize = 10
}
searchData := new(authorized_service.SearchData)
searchData.Page = page
searchData.PageSize = pageSize
searchData.BusinessKey = req.BusinessKey
searchData.BusinessSecret = req.BusinessSecret
searchData.Remark = req.Remark
resListData, err := h.authorizedService.PageList(c, searchData)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.AuthorizedListError,
code.Text(code.AuthorizedListError)).WithErr(err),
)
return
}
resCountData, err := h.authorizedService.PageListCount(c, searchData)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.AuthorizedListError,
code.Text(code.AuthorizedListError)).WithErr(err),
)
return
}
res.Pagination.Total = cast.ToInt(resCountData)
res.Pagination.PrePageCount = pageSize
res.Pagination.CurrentPage = page
res.List = make([]listData, len(resListData))
for k, v := range resListData {
hashId, err := h.hashids.HashidsEncode([]int{cast.ToInt(v.Id)})
if err != nil {
h.logger.Info("hashids err", zap.Error(err))
}
data := listData{
Id: cast.ToInt(v.Id),
HashID: hashId,
BusinessKey: v.BusinessKey,
BusinessSecret: v.BusinessSecret,
BusinessDeveloper: v.BusinessDeveloper,
Remark: v.Remark,
IsUsed: cast.ToInt(v.IsUsed),
CreatedAt: v.CreatedAt.Format(time_parse.CSTLayout),
CreatedUser: v.CreatedUser,
UpdatedAt: v.UpdatedAt.Format(time_parse.CSTLayout),
UpdatedUser: v.UpdatedUser,
}
res.List[k] = data
}
c.Payload(res)
}
}

View File

@@ -0,0 +1,109 @@
package authorized_handler
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/code"
"github.com/xinliangnote/go-gin-api/internal/api/service/authorized_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/spf13/cast"
"go.uber.org/zap"
)
type listAPIRequest struct {
Id string `form:"id"` // hashID
}
type listAPIData struct {
HashId string `json:"hash_id"` // hashID
BusinessKey string `json:"business_key"` // 调用方key
Method string `json:"method"` // 调用方secret
API string `json:"api"` // 调用方对接人
}
type listAPIResponse struct {
List []listAPIData `json:"list"`
}
// ListAPI 调用方接口地址列表
// @Summary 调用方接口地址列表
// @Description 调用方接口地址列表
// @Tags API.authorized
// @Accept json
// @Produce json
// @Param business_key query string false "调用方key"
// @Success 200 {object} listAPIResponse
// @Failure 400 {object} code.Failure
// @Router /api/authorized_api [get]
func (h *handler) ListAPI() core.HandlerFunc {
return func(c core.Context) {
req := new(listAPIRequest)
res := new(listAPIResponse)
if err := c.ShouldBindForm(req); err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
)
return
}
id := int32(ids[0])
// 通过 id 查询出 business_key
authorizedInfo, err := h.authorizedService.Detail(c, id)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.AuthorizedDetailError,
code.Text(code.AuthorizedDetailError)).WithErr(err),
)
return
}
searchAPIData := new(authorized_service.SearchAPIData)
searchAPIData.BusinessKey = authorizedInfo.BusinessKey
resListData, err := h.authorizedService.ListAPI(c, searchAPIData)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.AuthorizedListAPIError,
code.Text(code.AuthorizedListAPIError)).WithErr(err),
)
return
}
res.List = make([]listAPIData, len(resListData))
for k, v := range resListData {
hashId, err := h.hashids.HashidsEncode([]int{cast.ToInt(v.Id)})
if err != nil {
h.logger.Info("hashids err", zap.Error(err))
}
data := listAPIData{
HashId: hashId,
BusinessKey: v.BusinessKey,
Method: v.Method,
API: v.Api,
}
res.List[k] = data
}
c.Payload(res)
}
}

View File

@@ -0,0 +1,68 @@
package authorized_handler
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type updateUsedRequest struct {
Id string `json:"id"` // 主键ID
Used int32 `json:"used"` // 是否启用 1:是 -1:否
}
type updateUsedResponse struct {
Id int32 `json:"id"` // 主键ID
}
// UpdateUsed 更新调用方为启用/禁用
// @Summary 更新调用方为启用/禁用
// @Description 更新调用方为启用/禁用
// @Tags API.authorized
// @Accept json
// @Produce json
// @Param Request body updateUsedRequest true "请求信息"
// @Success 200 {object} updateUsedResponse
// @Failure 400 {object} code.Failure
// @Router /api/authorized/used [patch]
func (h *handler) UpdateUsed() core.HandlerFunc {
return func(c core.Context) {
req := new(updateUsedRequest)
res := new(updateUsedResponse)
if err := c.ShouldBindJSON(req); err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
)
return
}
ids, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
)
return
}
id := int32(ids[0])
err = h.authorizedService.UpdateUsed(c, id, req.Used)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.AuthorizedUpdateError,
code.Text(code.AuthorizedUpdateError)).WithErr(err),
)
return
}
res.Id = id
c.Payload(res)
}
}

View File

@@ -0,0 +1,71 @@
package authorized_handler
import (
"github.com/xinliangnote/go-gin-api/configs"
"github.com/xinliangnote/go-gin-api/internal/api/service/authorized_service"
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
"github.com/xinliangnote/go-gin-api/pkg/hash"
"go.uber.org/zap"
)
var _ Handler = (*handler)(nil)
type Handler interface {
i()
// Create 新增调用方
// @Tags API.authorized
// @Router /api/authorized [post]
Create() core.HandlerFunc
// CreateAPI 授权调用方接口地址
// @Tags API.authorized
// @Router /api/authorized_api [post]
CreateAPI() core.HandlerFunc
// List 调用方列表
// @Tags API.authorized
// @Router /api/authorized [get]
List() core.HandlerFunc
// ListAPI 调用方接口地址列表
// @Tags API.authorized
// @Router /api/authorized_api [get]
ListAPI() core.HandlerFunc
// Delete 删除调用方
// @Tags API.authorized
// @Router /api/authorized/{id} [delete]
Delete() core.HandlerFunc
// DeleteAPI 删除调用方接口地址
// @Tags API.authorized
// @Router /api/authorized_api/{id} [delete]
DeleteAPI() core.HandlerFunc
// UpdateUsed 更新调用方为启用/禁用
// @Tags API.authorized
// @Router /api/authorized/used [patch]
UpdateUsed() core.HandlerFunc
}
type handler struct {
logger *zap.Logger
cache cache.Repo
authorizedService authorized_service.Service
hashids hash.Hash
}
func New(logger *zap.Logger, db db.Repo, cache cache.Repo) Handler {
return &handler{
logger: logger,
cache: cache,
authorizedService: authorized_service.New(db, cache),
hashids: hash.New(configs.Get().HashIds.Secret, configs.Get().HashIds.Length),
}
}
func (h *handler) i() {}

View File

@@ -0,0 +1,56 @@
package tool_handler
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type hashIdsDecodeRequest struct {
Id string `uri:"id"` // 需解密的密文
}
type hashIdsDecodeResponse struct {
Val int `json:"val"` // 解密后的值
}
// HashIdsDecode HashIds 解密
// @Summary HashIds 解密
// @Description HashIds 解密
// @Tags API.tool
// @Accept json
// @Produce json
// @Param id path string true "需解密的密文"
// @Success 200 {object} hashIdsDecodeResponse
// @Failure 400 {object} code.Failure
// @Router /api/tool/hashids/decode/{id} [get]
func (h *handler) HashIdsDecode() core.HandlerFunc {
return func(c core.Context) {
req := new(hashIdsDecodeRequest)
res := new(hashIdsDecodeResponse)
if err := c.ShouldBindURI(req); err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
)
return
}
hashId, err := h.hashids.HashidsDecode(req.Id)
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
)
return
}
res.Val = hashId[0]
c.Payload(res)
}
}

View File

@@ -0,0 +1,58 @@
package tool_handler
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
"github.com/spf13/cast"
)
type hashIdsEncodeRequest struct {
Id int32 `uri:"id"` // 需加密的数字
}
type hashIdsEncodeResponse struct {
Val string `json:"val"` // 加密后的值
}
// HashIdsEncode HashIds 加密
// @Summary HashIds 加密
// @Description HashIds 加密
// @Tags API.tool
// @Accept json
// @Produce json
// @Param id path string true "需加密的数字"
// @Success 200 {object} hashIdsEncodeResponse
// @Failure 400 {object} code.Failure
// @Router /api/tool/hashids/encode/{id} [get]
func (h *handler) HashIdsEncode() core.HandlerFunc {
return func(c core.Context) {
req := new(hashIdsEncodeRequest)
res := new(hashIdsEncodeResponse)
if err := c.ShouldBindURI(req); err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
)
return
}
hashId, err := h.hashids.HashidsEncode([]int{cast.ToInt(req.Id)})
if err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.HashIdsDecodeError,
code.Text(code.HashIdsDecodeError)).WithErr(err),
)
return
}
res.Val = hashId
c.Payload(res)
}
}

View File

@@ -0,0 +1,43 @@
package tool_handler
import (
"github.com/xinliangnote/go-gin-api/configs"
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
"github.com/xinliangnote/go-gin-api/pkg/hash"
"go.uber.org/zap"
)
var _ Handler = (*handler)(nil)
type Handler interface {
i()
// HashIdsEncode HashIds 加密
// @Tags API.tool
// @Router /api/tool/hashids/encode/{id} [get]
HashIdsEncode() core.HandlerFunc
// HashIdsDecode HashIds 解密
// @Tags API.tool
// @Router /api/tool/hashids/decode/{id} [get]
HashIdsDecode() core.HandlerFunc
}
type handler struct {
logger *zap.Logger
cache cache.Repo
hashids hash.Hash
}
func New(logger *zap.Logger, db db.Repo, cache cache.Repo) Handler {
return &handler{
logger: logger,
cache: cache,
hashids: hash.New(configs.Get().HashIds.Secret, configs.Get().HashIds.Length),
}
}
func (h *handler) i() {}

View File

@@ -0,0 +1,497 @@
///////////////////////////////////////////////////////////
// THIS FILE IS AUTO GENERATED by gormgen, DON'T EDIT IT //
// ANY CHANGES DONE HERE WILL BE LOST //
///////////////////////////////////////////////////////////
package authorized_api_repo
import (
"fmt"
"time"
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
"github.com/pkg/errors"
"gorm.io/gorm"
)
func NewModel() *AuthorizedApi {
return new(AuthorizedApi)
}
func NewQueryBuilder() *authorizedApiRepoQueryBuilder {
return new(authorizedApiRepoQueryBuilder)
}
func (t *AuthorizedApi) Create(db *gorm.DB) (id int32, err error) {
if err = db.Create(t).Error; err != nil {
return 0, errors.Wrap(err, "create err")
}
return t.Id, nil
}
func (t *AuthorizedApi) Delete(db *gorm.DB) (err error) {
if err = db.Delete(t).Error; err != nil {
return errors.Wrap(err, "delete err")
}
return nil
}
func (t *AuthorizedApi) Updates(db *gorm.DB, m map[string]interface{}) (err error) {
if err = db.Model(&AuthorizedApi{}).Where("id = ?", t.Id).Updates(m).Error; err != nil {
return errors.Wrap(err, "updates err")
}
return nil
}
type authorizedApiRepoQueryBuilder struct {
order []string
where []struct {
prefix string
value interface{}
}
limit int
offset int
}
func (qb *authorizedApiRepoQueryBuilder) buildQuery(db *gorm.DB) *gorm.DB {
ret := db
for _, where := range qb.where {
ret = ret.Where(where.prefix, where.value)
}
for _, order := range qb.order {
ret = ret.Order(order)
}
ret = ret.Limit(qb.limit).Offset(qb.offset)
return ret
}
func (qb *authorizedApiRepoQueryBuilder) Count(db *gorm.DB) (int64, error) {
var c int64
res := qb.buildQuery(db).Model(&AuthorizedApi{}).Count(&c)
if res.Error != nil && res.Error == gorm.ErrRecordNotFound {
c = 0
}
return c, res.Error
}
func (qb *authorizedApiRepoQueryBuilder) First(db *gorm.DB) (*AuthorizedApi, error) {
ret := &AuthorizedApi{}
res := qb.buildQuery(db).First(ret)
if res.Error != nil && res.Error == gorm.ErrRecordNotFound {
ret = nil
}
return ret, res.Error
}
func (qb *authorizedApiRepoQueryBuilder) QueryOne(db *gorm.DB) (*AuthorizedApi, error) {
qb.limit = 1
ret, err := qb.QueryAll(db)
if len(ret) > 0 {
return ret[0], err
}
return nil, err
}
func (qb *authorizedApiRepoQueryBuilder) QueryAll(db *gorm.DB) ([]*AuthorizedApi, error) {
var ret []*AuthorizedApi
err := qb.buildQuery(db).Find(&ret).Error
return ret, err
}
func (qb *authorizedApiRepoQueryBuilder) Limit(limit int) *authorizedApiRepoQueryBuilder {
qb.limit = limit
return qb
}
func (qb *authorizedApiRepoQueryBuilder) Offset(offset int) *authorizedApiRepoQueryBuilder {
qb.offset = offset
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereId(p db_repo.Predicate, value int32) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "id", p),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereIdIn(value []int32) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "id", "IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereIdNotIn(value []int32) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "id", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) OrderById(asc bool) *authorizedApiRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "id "+order)
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereBusinessKey(p db_repo.Predicate, value string) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "business_key", p),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereBusinessKeyIn(value []string) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "business_key", "IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereBusinessKeyNotIn(value []string) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "business_key", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) OrderByBusinessKey(asc bool) *authorizedApiRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "business_key "+order)
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereMethod(p db_repo.Predicate, value string) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "method", p),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereMethodIn(value []string) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "method", "IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereMethodNotIn(value []string) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "method", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) OrderByMethod(asc bool) *authorizedApiRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "method "+order)
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereApi(p db_repo.Predicate, value string) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "api", p),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereApiIn(value []string) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "api", "IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereApiNotIn(value []string) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "api", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) OrderByApi(asc bool) *authorizedApiRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "api "+order)
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereIsDeleted(p db_repo.Predicate, value int32) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "is_deleted", p),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereIsDeletedIn(value []int32) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "is_deleted", "IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereIsDeletedNotIn(value []int32) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "is_deleted", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) OrderByIsDeleted(asc bool) *authorizedApiRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "is_deleted "+order)
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereCreatedAt(p db_repo.Predicate, value time.Time) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "created_at", p),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereCreatedAtIn(value []time.Time) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "created_at", "IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereCreatedAtNotIn(value []time.Time) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "created_at", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) OrderByCreatedAt(asc bool) *authorizedApiRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "created_at "+order)
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereCreatedUser(p db_repo.Predicate, value string) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "created_user", p),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereCreatedUserIn(value []string) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "created_user", "IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereCreatedUserNotIn(value []string) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "created_user", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) OrderByCreatedUser(asc bool) *authorizedApiRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "created_user "+order)
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereUpdatedAt(p db_repo.Predicate, value time.Time) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "updated_at", p),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereUpdatedAtIn(value []time.Time) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "updated_at", "IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereUpdatedAtNotIn(value []time.Time) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "updated_at", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) OrderByUpdatedAt(asc bool) *authorizedApiRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "updated_at "+order)
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereUpdatedUser(p db_repo.Predicate, value string) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "updated_user", p),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereUpdatedUserIn(value []string) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "updated_user", "IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) WhereUpdatedUserNotIn(value []string) *authorizedApiRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "updated_user", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedApiRepoQueryBuilder) OrderByUpdatedUser(asc bool) *authorizedApiRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "updated_user "+order)
return qb
}

View File

@@ -0,0 +1,17 @@
package authorized_api_repo
import "time"
// 已授权的调用方表
//go:generate gormgen -structs AuthorizedApi -input .
type AuthorizedApi struct {
Id int32 // 主键
BusinessKey string // 调用方key
Method string // 请求方式
Api string // 请求地址
IsDeleted int32 // 是否删除 1:是 -1:否
CreatedAt time.Time `gorm:"time"` // 创建时间
CreatedUser string // 创建人
UpdatedAt time.Time `gorm:"time"` // 更新时间
UpdatedUser string // 更新人
}

View File

@@ -0,0 +1,14 @@
#### go_gin_api.authorized_api
已授权的调用方表
| 序号 | 名称 | 描述 | 类型 | 键 | 为空 | 额外 | 默认值 |
| :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: |
| 1 | id | 主键 | int(11) unsigned | PRI | NO | auto_increment | |
| 2 | business_key | 调用方key | varchar(30) | | NO | | |
| 3 | method | 请求方式 | varchar(30) | | NO | | |
| 4 | api | 请求地址 | varchar(100) | | NO | | |
| 5 | is_deleted | 是否删除 1:是 -1:否 | tinyint(1) | | NO | | -1 |
| 6 | created_at | 创建时间 | timestamp | | NO | | CURRENT_TIMESTAMP |
| 7 | created_user | 创建人 | varchar(60) | | NO | | |
| 8 | updated_at | 更新时间 | timestamp | | NO | on update CURRENT_TIMESTAMP | CURRENT_TIMESTAMP |
| 9 | updated_user | 更新人 | varchar(60) | | NO | | |

View File

@@ -0,0 +1,583 @@
///////////////////////////////////////////////////////////
// THIS FILE IS AUTO GENERATED by gormgen, DON'T EDIT IT //
// ANY CHANGES DONE HERE WILL BE LOST //
///////////////////////////////////////////////////////////
package authorized_repo
import (
"fmt"
"time"
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
"github.com/pkg/errors"
"gorm.io/gorm"
)
func NewModel() *Authorized {
return new(Authorized)
}
func NewQueryBuilder() *authorizedRepoQueryBuilder {
return new(authorizedRepoQueryBuilder)
}
func (t *Authorized) Create(db *gorm.DB) (id int32, err error) {
if err = db.Create(t).Error; err != nil {
return 0, errors.Wrap(err, "create err")
}
return t.Id, nil
}
func (t *Authorized) Delete(db *gorm.DB) (err error) {
if err = db.Delete(t).Error; err != nil {
return errors.Wrap(err, "delete err")
}
return nil
}
func (t *Authorized) Updates(db *gorm.DB, m map[string]interface{}) (err error) {
if err = db.Model(&Authorized{}).Where("id = ?", t.Id).Updates(m).Error; err != nil {
return errors.Wrap(err, "updates err")
}
return nil
}
type authorizedRepoQueryBuilder struct {
order []string
where []struct {
prefix string
value interface{}
}
limit int
offset int
}
func (qb *authorizedRepoQueryBuilder) buildQuery(db *gorm.DB) *gorm.DB {
ret := db
for _, where := range qb.where {
ret = ret.Where(where.prefix, where.value)
}
for _, order := range qb.order {
ret = ret.Order(order)
}
ret = ret.Limit(qb.limit).Offset(qb.offset)
return ret
}
func (qb *authorizedRepoQueryBuilder) Count(db *gorm.DB) (int64, error) {
var c int64
res := qb.buildQuery(db).Model(&Authorized{}).Count(&c)
if res.Error != nil && res.Error == gorm.ErrRecordNotFound {
c = 0
}
return c, res.Error
}
func (qb *authorizedRepoQueryBuilder) First(db *gorm.DB) (*Authorized, error) {
ret := &Authorized{}
res := qb.buildQuery(db).First(ret)
if res.Error != nil && res.Error == gorm.ErrRecordNotFound {
ret = nil
}
return ret, res.Error
}
func (qb *authorizedRepoQueryBuilder) QueryOne(db *gorm.DB) (*Authorized, error) {
qb.limit = 1
ret, err := qb.QueryAll(db)
if len(ret) > 0 {
return ret[0], err
}
return nil, err
}
func (qb *authorizedRepoQueryBuilder) QueryAll(db *gorm.DB) ([]*Authorized, error) {
var ret []*Authorized
err := qb.buildQuery(db).Find(&ret).Error
return ret, err
}
func (qb *authorizedRepoQueryBuilder) Limit(limit int) *authorizedRepoQueryBuilder {
qb.limit = limit
return qb
}
func (qb *authorizedRepoQueryBuilder) Offset(offset int) *authorizedRepoQueryBuilder {
qb.offset = offset
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereId(p db_repo.Predicate, value int32) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "id", p),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereIdIn(value []int32) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "id", "IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereIdNotIn(value []int32) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "id", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) OrderById(asc bool) *authorizedRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "id "+order)
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereBusinessKey(p db_repo.Predicate, value string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "business_key", p),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereBusinessKeyIn(value []string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "business_key", "IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereBusinessKeyNotIn(value []string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "business_key", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) OrderByBusinessKey(asc bool) *authorizedRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "business_key "+order)
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereBusinessSecret(p db_repo.Predicate, value string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "business_secret", p),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereBusinessSecretIn(value []string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "business_secret", "IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereBusinessSecretNotIn(value []string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "business_secret", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) OrderByBusinessSecret(asc bool) *authorizedRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "business_secret "+order)
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereBusinessDeveloper(p db_repo.Predicate, value string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "business_developer", p),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereBusinessDeveloperIn(value []string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "business_developer", "IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereBusinessDeveloperNotIn(value []string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "business_developer", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) OrderByBusinessDeveloper(asc bool) *authorizedRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "business_developer "+order)
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereRemark(p db_repo.Predicate, value string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "remark", p),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereRemarkIn(value []string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "remark", "IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereRemarkNotIn(value []string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "remark", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) OrderByRemark(asc bool) *authorizedRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "remark "+order)
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereIsUsed(p db_repo.Predicate, value int32) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "is_used", p),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereIsUsedIn(value []int32) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "is_used", "IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereIsUsedNotIn(value []int32) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "is_used", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) OrderByIsUsed(asc bool) *authorizedRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "is_used "+order)
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereIsDeleted(p db_repo.Predicate, value int32) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "is_deleted", p),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereIsDeletedIn(value []int32) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "is_deleted", "IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereIsDeletedNotIn(value []int32) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "is_deleted", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) OrderByIsDeleted(asc bool) *authorizedRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "is_deleted "+order)
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereCreatedAt(p db_repo.Predicate, value time.Time) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "created_at", p),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereCreatedAtIn(value []time.Time) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "created_at", "IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereCreatedAtNotIn(value []time.Time) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "created_at", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) OrderByCreatedAt(asc bool) *authorizedRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "created_at "+order)
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereCreatedUser(p db_repo.Predicate, value string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "created_user", p),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereCreatedUserIn(value []string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "created_user", "IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereCreatedUserNotIn(value []string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "created_user", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) OrderByCreatedUser(asc bool) *authorizedRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "created_user "+order)
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereUpdatedAt(p db_repo.Predicate, value time.Time) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "updated_at", p),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereUpdatedAtIn(value []time.Time) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "updated_at", "IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereUpdatedAtNotIn(value []time.Time) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "updated_at", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) OrderByUpdatedAt(asc bool) *authorizedRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "updated_at "+order)
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereUpdatedUser(p db_repo.Predicate, value string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "updated_user", p),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereUpdatedUserIn(value []string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "updated_user", "IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) WhereUpdatedUserNotIn(value []string) *authorizedRepoQueryBuilder {
qb.where = append(qb.where, struct {
prefix string
value interface{}
}{
fmt.Sprintf("%v %v ?", "updated_user", "NOT IN"),
value,
})
return qb
}
func (qb *authorizedRepoQueryBuilder) OrderByUpdatedUser(asc bool) *authorizedRepoQueryBuilder {
order := "DESC"
if asc {
order = "ASC"
}
qb.order = append(qb.order, "updated_user "+order)
return qb
}

View File

@@ -0,0 +1,19 @@
package authorized_repo
import "time"
// 已授权的调用方表
//go:generate gormgen -structs Authorized -input .
type Authorized struct {
Id int32 // 主键
BusinessKey string // 调用方key
BusinessSecret string // 调用方secret
BusinessDeveloper string // 调用方对接人
Remark string // 备注
IsUsed int32 // 是否启用 1:是 -1:否
IsDeleted int32 // 是否删除 1:是 -1:否
CreatedAt time.Time `gorm:"time"` // 创建时间
CreatedUser string // 创建人
UpdatedAt time.Time `gorm:"time"` // 更新时间
UpdatedUser string // 更新人
}

View File

@@ -0,0 +1,16 @@
#### go_gin_api.authorized
已授权的调用方表
| 序号 | 名称 | 描述 | 类型 | 键 | 为空 | 额外 | 默认值 |
| :--: | :--: | :--: | :--: | :--: | :--: | :--: | :--: |
| 1 | id | 主键 | int(11) unsigned | PRI | NO | auto_increment | |
| 2 | business_key | 调用方key | varchar(32) | | NO | | |
| 3 | business_secret | 调用方secret | varchar(60) | | NO | | |
| 4 | business_developer | 调用方对接人 | varchar(60) | | NO | | |
| 5 | remark | 备注 | varchar(255) | | NO | | |
| 6 | is_used | 是否启用 1:是 -1:否 | tinyint(1) | | NO | | -1 |
| 7 | is_deleted | 是否删除 1:是 -1:否 | tinyint(1) | | NO | | -1 |
| 8 | created_at | 创建时间 | timestamp | | NO | | CURRENT_TIMESTAMP |
| 9 | created_user | 创建人 | varchar(60) | | NO | | |
| 10 | updated_at | 更新时间 | timestamp | | NO | on update CURRENT_TIMESTAMP | CURRENT_TIMESTAMP |
| 11 | updated_user | 更新人 | varchar(60) | | NO | | |

View File

@@ -0,0 +1,41 @@
package authorized_service
import (
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_api_repo"
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_repo"
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
)
var _ Service = (*service)(nil)
type Service interface {
i()
Create(ctx core.Context, authorizedData *CreateAuthorizedData) (id int32, err error)
List(ctx core.Context, searchData *SearchData) (listData []*authorized_repo.Authorized, err error)
PageList(ctx core.Context, searchData *SearchData) (listData []*authorized_repo.Authorized, err error)
PageListCount(ctx core.Context, searchData *SearchData) (total int64, err error)
UpdateUsed(ctx core.Context, id int32, used int32) (err error)
Delete(ctx core.Context, id int32) (err error)
Detail(ctx core.Context, id int32) (info *authorized_repo.Authorized, err error)
CreateAPI(ctx core.Context, authorizedAPIData *CreateAuthorizedAPIData) (id int32, err error)
ListAPI(ctx core.Context, searchAPIData *SearchAPIData) (listData []*authorized_api_repo.AuthorizedApi, err error)
DeleteAPI(ctx core.Context, id int32) (err error)
}
type service struct {
db db.Repo
cache cache.Repo
}
func New(db db.Repo, cache cache.Repo) Service {
return &service{
db: db,
cache: cache,
}
}
func (s *service) i() {}

View File

@@ -0,0 +1,37 @@
package authorized_service
import (
"crypto/rand"
"encoding/hex"
"io"
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_repo"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
)
type CreateAuthorizedData struct {
BusinessKey string `json:"business_key"` // 调用方key
BusinessDeveloper string `json:"business_developer"` // 调用方对接人
Remark string `json:"remark"` // 备注
}
func (s *service) Create(ctx core.Context, authorizedData *CreateAuthorizedData) (id int32, err error) {
buf := make([]byte, 10)
io.ReadFull(rand.Reader, buf)
secret := string(hex.EncodeToString(buf))
model := authorized_repo.NewModel()
model.BusinessKey = authorizedData.BusinessKey
model.BusinessSecret = secret
model.BusinessDeveloper = authorizedData.BusinessDeveloper
model.Remark = authorizedData.Remark
model.CreatedUser = "system" // TODO
model.IsUsed = 1
model.IsDeleted = -1
id, err = model.Create(s.db.GetDbW().WithContext(ctx.RequestContext()))
if err != nil {
return 0, err
}
return
}

View File

@@ -0,0 +1,27 @@
package authorized_service
import (
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_api_repo"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
)
type CreateAuthorizedAPIData struct {
BusinessKey string `json:"business_key"` // 调用方key
Method string `json:"method"` // 请求方法
API string `json:"api"` // 请求地址
}
func (s *service) CreateAPI(ctx core.Context, authorizedAPIData *CreateAuthorizedAPIData) (id int32, err error) {
model := authorized_api_repo.NewModel()
model.BusinessKey = authorizedAPIData.BusinessKey
model.Method = authorizedAPIData.Method
model.Api = authorizedAPIData.API
model.CreatedUser = "system" // TODO
model.IsDeleted = -1
id, err = model.Create(s.db.GetDbW().WithContext(ctx.RequestContext()))
if err != nil {
return 0, err
}
return
}

View File

@@ -0,0 +1,23 @@
package authorized_service
import (
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_repo"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
)
func (s *service) Delete(ctx core.Context, id int32) (err error) {
model := authorized_repo.NewModel()
model.Id = id
data := map[string]interface{}{
"is_deleted": 1,
"updated_user": "system", // TODO
}
err = model.Updates(s.db.GetDbW().WithContext(ctx.RequestContext()), data)
if err != nil {
return err
}
return
}

View File

@@ -0,0 +1,23 @@
package authorized_service
import (
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_api_repo"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
)
func (s *service) DeleteAPI(ctx core.Context, id int32) (err error) {
model := authorized_api_repo.NewModel()
model.Id = id
data := map[string]interface{}{
"is_deleted": 1,
"updated_user": "system", // TODO
}
err = model.Updates(s.db.GetDbW().WithContext(ctx.RequestContext()), data)
if err != nil {
return err
}
return
}

View File

@@ -0,0 +1,21 @@
package authorized_service
import (
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_repo"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
)
func (s *service) Detail(ctx core.Context, id int32) (info *authorized_repo.Authorized, err error) {
qb := authorized_repo.NewQueryBuilder()
qb = qb.WhereIsDeleted(db_repo.EqualPredicate, -1)
qb.WhereId(db_repo.EqualPredicate, id)
info, err = qb.First(s.db.GetDbR().WithContext(ctx.RequestContext()))
if err != nil {
return nil, err
}
return
}

View File

@@ -0,0 +1,34 @@
package authorized_service
import (
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_repo"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
)
func (s *service) List(ctx core.Context, searchData *SearchData) (listData []*authorized_repo.Authorized, err error) {
qb := authorized_repo.NewQueryBuilder()
qb = qb.WhereIsDeleted(db_repo.EqualPredicate, -1)
if searchData.BusinessKey != "" {
qb.WhereBusinessKey(db_repo.EqualPredicate, searchData.BusinessKey)
}
if searchData.BusinessSecret != "" {
qb.WhereBusinessSecret(db_repo.EqualPredicate, searchData.BusinessSecret)
}
if searchData.BusinessDeveloper != "" {
qb.WhereBusinessDeveloper(db_repo.EqualPredicate, searchData.BusinessDeveloper)
}
listData, err = qb.
OrderById(false).
QueryAll(s.db.GetDbR().WithContext(ctx.RequestContext()))
if err != nil {
return nil, err
}
return
}

View File

@@ -0,0 +1,30 @@
package authorized_service
import (
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_api_repo"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
)
type SearchAPIData struct {
BusinessKey string `json:"business_key"` // 调用方key
}
func (s *service) ListAPI(ctx core.Context, searchAPIData *SearchAPIData) (listData []*authorized_api_repo.AuthorizedApi, err error) {
qb := authorized_api_repo.NewQueryBuilder()
qb = qb.WhereIsDeleted(db_repo.EqualPredicate, -1)
if searchAPIData.BusinessKey != "" {
qb.WhereBusinessKey(db_repo.EqualPredicate, searchAPIData.BusinessKey)
}
listData, err = qb.
OrderById(false).
QueryAll(s.db.GetDbR().WithContext(ctx.RequestContext()))
if err != nil {
return nil, err
}
return
}

View File

@@ -0,0 +1,57 @@
package authorized_service
import (
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_repo"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
)
type SearchData struct {
Page int `json:"page"` // 第几页
PageSize int `json:"page_size"` // 每页显示条数
BusinessKey string `json:"business_key"` // 调用方key
BusinessSecret string `json:"business_secret"` // 调用方secret
BusinessDeveloper string `json:"business_developer"` // 调用方对接人
Remark string `json:"remark"` // 备注
}
func (s *service) PageList(ctx core.Context, searchData *SearchData) (listData []*authorized_repo.Authorized, err error) {
page := searchData.Page
if page == 0 {
page = 1
}
pageSize := searchData.PageSize
if pageSize == 0 {
pageSize = 10
}
offset := (page - 1) * pageSize
qb := authorized_repo.NewQueryBuilder()
qb = qb.WhereIsDeleted(db_repo.EqualPredicate, -1)
if searchData.BusinessKey != "" {
qb.WhereBusinessKey(db_repo.EqualPredicate, searchData.BusinessKey)
}
if searchData.BusinessSecret != "" {
qb.WhereBusinessSecret(db_repo.EqualPredicate, searchData.BusinessSecret)
}
if searchData.BusinessDeveloper != "" {
qb.WhereBusinessDeveloper(db_repo.EqualPredicate, searchData.BusinessDeveloper)
}
listData, err = qb.
Limit(pageSize).
Offset(offset).
OrderById(false).
QueryAll(s.db.GetDbR().WithContext(ctx.RequestContext()))
if err != nil {
return nil, err
}
return
}

View File

@@ -0,0 +1,31 @@
package authorized_service
import (
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo"
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_repo"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
)
func (s *service) PageListCount(ctx core.Context, searchData *SearchData) (total int64, err error) {
qb := authorized_repo.NewQueryBuilder()
qb = qb.WhereIsDeleted(db_repo.EqualPredicate, -1)
if searchData.BusinessKey != "" {
qb.WhereBusinessKey(db_repo.EqualPredicate, searchData.BusinessKey)
}
if searchData.BusinessSecret != "" {
qb.WhereBusinessSecret(db_repo.EqualPredicate, searchData.BusinessSecret)
}
if searchData.BusinessDeveloper != "" {
qb.WhereBusinessDeveloper(db_repo.EqualPredicate, searchData.BusinessDeveloper)
}
total, err = qb.Count(s.db.GetDbR().WithContext(ctx.RequestContext()))
if err != nil {
return 0, err
}
return
}

View File

@@ -0,0 +1,23 @@
package authorized_service
import (
"github.com/xinliangnote/go-gin-api/internal/api/repository/db_repo/authorized_repo"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
)
func (s *service) UpdateUsed(ctx core.Context, id int32, used int32) (err error) {
model := authorized_repo.NewModel()
model.Id = id
data := map[string]interface{}{
"is_used": used,
"updated_user": "system", // TODO
}
err = model.Updates(s.db.GetDbW().WithContext(ctx.RequestContext()), data)
if err != nil {
return err
}
return
}

View File

@@ -1,7 +1,9 @@
package router
import (
"github.com/xinliangnote/go-gin-api/internal/api/controller/authorized_handler"
"github.com/xinliangnote/go-gin-api/internal/api/controller/demo_handler"
"github.com/xinliangnote/go-gin-api/internal/api/controller/tool_handler"
"github.com/xinliangnote/go-gin-api/internal/api/controller/user_handler"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
)
@@ -33,4 +35,24 @@ func setApiRouter(r *resource) {
user.PATCH("/delete/:id", userHandler.Delete())
user.GET("/info/:username", core.AliasForRecordMetrics("/user/info"), userHandler.Detail())
}
// api
api := r.mux.Group("/api")
{
// authorized
authorizedHandler := authorized_handler.New(r.logger, r.db, r.cache)
api.POST("/authorized", authorizedHandler.Create())
api.GET("/authorized", authorizedHandler.List())
api.PATCH("/authorized/used", authorizedHandler.UpdateUsed())
api.DELETE("/authorized/:id", authorizedHandler.Delete())
api.POST("/authorized_api", authorizedHandler.CreateAPI())
api.GET("/authorized_list", authorizedHandler.ListAPI())
api.DELETE("/authorized_api/:id", authorizedHandler.DeleteAPI())
// tool
toolHandler := tool_handler.New(r.logger, r.db, r.cache)
api.GET("/tool/hashids/encode/:id", toolHandler.HashIdsEncode())
api.GET("/tool/hashids/decode/:id", toolHandler.HashIdsDecode())
}
}

View File

@@ -1,10 +1,12 @@
package router
import (
"github.com/xinliangnote/go-gin-api/internal/web/controller/authorized_handler"
"github.com/xinliangnote/go-gin-api/internal/web/controller/configinfo_handler"
"github.com/xinliangnote/go-gin-api/internal/web/controller/dashboard_handler"
"github.com/xinliangnote/go-gin-api/internal/web/controller/gencode_handler"
"github.com/xinliangnote/go-gin-api/internal/web/controller/index_handler"
"github.com/xinliangnote/go-gin-api/internal/web/controller/tool_handler"
)
func setWebRouter(r *resource) {
@@ -13,6 +15,8 @@ func setWebRouter(r *resource) {
dashboardHandler := dashboard_handler.New(r.logger, r.db, r.cache)
genCodeHandler := gencode_handler.New(r.logger, r.db, r.cache)
configInfoHandler := configinfo_handler.New(r.logger, r.db, r.cache)
authorizedHandler := authorized_handler.New(r.logger, r.db, r.cache)
toolHandler := tool_handler.New(r.logger, r.db, r.cache)
web := r.mux.Group("", r.middles.DisableLog())
{
@@ -35,5 +39,13 @@ func setWebRouter(r *resource) {
web.GET("/handlergen", genCodeHandler.HandlerView())
web.POST("/handlergen_exec", genCodeHandler.HandlerExecute())
// 调用方
web.GET("/authorized/list", authorizedHandler.ListView())
web.GET("/authorized/add", authorizedHandler.AddView())
web.GET("/authorized/api/:id", authorizedHandler.ApiView())
// 工具箱
web.GET("/tool/hashids", toolHandler.HashIdsView())
}
}

View File

@@ -0,0 +1,9 @@
package authorized_handler
import "github.com/xinliangnote/go-gin-api/internal/pkg/core"
func (h *handler) AddView() core.HandlerFunc {
return func(c core.Context) {
c.HTML("authorized_add", nil)
}
}

View File

@@ -0,0 +1,36 @@
package authorized_handler
import (
"net/http"
"github.com/xinliangnote/go-gin-api/internal/api/code"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/pkg/errno"
)
type apiViewRequest struct {
Id string `uri:"id"` // 主键ID
}
type apiViewResponse struct {
HashID string `json:"hash_id"` // hashID
}
func (h *handler) ApiView() core.HandlerFunc {
return func(c core.Context) {
req := new(apiViewRequest)
if err := c.ShouldBindURI(req); err != nil {
c.AbortWithError(errno.NewError(
http.StatusBadRequest,
code.ParamBindError,
code.Text(code.ParamBindError)).WithErr(err),
)
return
}
obj := new(apiViewResponse)
obj.HashID = req.Id
c.HTML("authorized_api", obj)
}
}

View File

@@ -0,0 +1,9 @@
package authorized_handler
import "github.com/xinliangnote/go-gin-api/internal/pkg/core"
func (h *handler) ListView() core.HandlerFunc {
return func(c core.Context) {
c.HTML("authorized_list", nil)
}
}

View File

@@ -0,0 +1,35 @@
package authorized_handler
import (
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
"go.uber.org/zap"
)
var _ Handler = (*handler)(nil)
type Handler interface {
i()
AddView() core.HandlerFunc
ApiView() core.HandlerFunc
ListView() core.HandlerFunc
}
type handler struct {
db db.Repo
logger *zap.Logger
cache cache.Repo
}
func New(logger *zap.Logger, db db.Repo, cache cache.Repo) Handler {
return &handler{
logger: logger,
cache: cache,
db: db,
}
}
func (h *handler) i() {}

View File

@@ -0,0 +1,12 @@
package tool_handler
import (
"github.com/xinliangnote/go-gin-api/configs"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
)
func (h *handler) HashIdsView() core.HandlerFunc {
return func(c core.Context) {
c.HTML("tool_hashids", configs.Get())
}
}

View File

@@ -0,0 +1,31 @@
package tool_handler
import (
"github.com/xinliangnote/go-gin-api/internal/pkg/cache"
"github.com/xinliangnote/go-gin-api/internal/pkg/core"
"github.com/xinliangnote/go-gin-api/internal/pkg/db"
"go.uber.org/zap"
)
var _ Handler = (*handler)(nil)
type Handler interface {
i()
HashIdsView() core.HandlerFunc
}
type handler struct {
logger *zap.Logger
cache cache.Repo
}
func New(logger *zap.Logger, db db.Repo, cache cache.Repo) Handler {
return &handler{
logger: logger,
cache: cache,
}
}
func (h *handler) i() {}

25
pkg/hash/hash.go Normal file
View File

@@ -0,0 +1,25 @@
package hash
var _ Hash = (*hash)(nil)
type Hash interface {
i()
// hashids
HashidsEncode(params []int) (string, error)
HashidsDecode(hash string) ([]int, error)
}
type hash struct {
secret string
length int
}
func New(secret string, length int) Hash {
return &hash{
secret: secret,
length: length,
}
}
func (h *hash) i() {}

41
pkg/hash/hash_hashids.go Normal file
View File

@@ -0,0 +1,41 @@
package hash
import (
"github.com/speps/go-hashids"
)
func (h *hash) HashidsEncode(params []int) (string, error) {
hd := hashids.NewData()
hd.Salt = h.secret
hd.MinLength = h.length
hashID, err := hashids.NewWithData(hd)
if err != nil {
return "", err
}
hashStr, err := hashID.Encode(params)
if err != nil {
return "", err
}
return hashStr, nil
}
func (h *hash) HashidsDecode(hash string) ([]int, error) {
hd := hashids.NewData()
hd.Salt = h.secret
hd.MinLength = h.length
hashID, err := hashids.NewWithData(hd)
if err != nil {
return nil, err
}
ids, err := hashID.DecodeWithError(hash)
if err != nil {
return nil, err
}
return ids, nil
}

View File

@@ -0,0 +1,18 @@
package hash
import "testing"
const secret = "i1ydX9RtHyuJTrw7frcu"
const length = 12
func TestHashidsEncode(t *testing.T) {
str, _ := New(secret, length).HashidsEncode([]int{99})
t.Log(str)
//GyV5pJqXvwAR
}
func TestHashidsDecode(t *testing.T) {
ids, _ := New(secret, length).HashidsDecode("GyV5pJqXvwAR")
t.Log(ids)
}