Цей скрипт не слід встановлювати безпосередньо. Це - бібліотека для інших скриптів для включення в мета директиву // @require https://update.greasyfork.org/scripts/520145/1500083/bsn-libs.js
/** 获取本地存储 */
window.getLocalStorage = function (key, defaultValue) {
return lscache.get(key) ?? defaultValue;
};
/** 设置本地存储 */
window.setLocalStorage = function (key, value) {
lscache.set(key, value);
};
/** 睡眠 */
window.sleep = function (time) {
return new Promise(resolve => setTimeout(resolve, time));
};
/** 获取粘贴板文字 */
window.getClipboardText = async function () {
if (navigator.clipboard && navigator.clipboard.readText) {
const text = await navigator.clipboard.readText();
return text;
}
return '';
};
/** 设置粘贴板文字 */
window.setClipboardText = async function (data) {
if (navigator.clipboard && navigator.clipboard.writeText) {
await navigator.clipboard.writeText(data);
}
};
/** 查找所有满足条件的元素 */
window.findAll = function (options) {
const { selectors, parent, findTarget } = options;
const parentEl =
parent && parent.tagName.toLocaleLowerCase() === 'iframe'
? parent.contentDocument.body
: parent;
const eles = Array.from((parentEl ?? document.body).querySelectorAll(selectors));
return findTarget ? eles.map((el, index) => findTarget(el, index)).filter(x => x) : eles;
};
/** 查找第一个满足条件的元素 */
window.find = function (options) {
const eles = window.findAll(options);
return eles.length > 0 ? eles[0] : null;
};
/** 查找最后一个满足条件的元素 */
window.findLast = function (options) {
const eles = window.findAll(options);
return eles.length > 0 ? eles[eles.length - 1] : null;
};
/** 模拟操作 */
window.simulateOperate = async function (actions) {
for (const action of actions) {
switch (action.type) {
case 'sleep':
await sleep(action.time);
break;
case 'focus':
case 'input':
case 'click':
const { selectors, value, parent, waiting, findTarget } = action;
if (waiting) await sleep(waiting);
const parentEl =
parent && parent.tagName.toLocaleLowerCase() === 'iframe'
? parent.contentDocument.body
: parent;
const eles = Array.from((parentEl ?? document.body).querySelectorAll(selectors));
const targets = findTarget
? eles.map((el, index) => findTarget(el, index)).filter(x => x)
: eles;
if (targets.length > 0) {
const target = targets[0];
if (action.type === 'focus' || action.focusable) target.focus();
if (action.type === 'input') {
target.value = value;
target.dispatchEvent(new Event('keydown'));
target.dispatchEvent(new Event('keypress'));
target.dispatchEvent(new Event('input'));
target.dispatchEvent(new Event('keyup'));
target.dispatchEvent(new Event('change'));
} else if (action.type === 'click') {
target.click();
}
}
break;
}
}
};
/** 创建naive对话框(增加异步功能且只能在组件的setup函数里调用) */
window.createNaiveDialog = function () {
const dialog = naive.useDialog();
['create', 'error', 'info', 'success', 'warning'].forEach(x => {
dialog[x + 'Async'] = options => {
return new Promise(resolve => {
dialog[x]({
...options,
onNegativeClick: () => resolve(false),
onPositiveClick: () => resolve(true)
});
});
};
});
return dialog;
};
/** 初始化Vue3(包括naive及自定义BTable组件) */
window.initVue3 = function (com) {
const style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = `
body {
text-align: left;
}
.app-wrapper .btn-toggle {
position: fixed;
top: 50vh;
right: 0;
padding-left: 12px;
padding-bottom: 4px;
transform: translateX(calc(100% - 32px)) translateY(-50%);
}
.drawer-wrapper .n-form {
margin: 0 8px;
}
.drawer-wrapper .n-form .n-form-item {
margin: 8px 0;
}
.drawer-wrapper .n-form .n-form-item .n-space {
flex: 1;
}
.drawer-wrapper .n-form .n-form-item .n-input-number {
width: 100%;
}
`;
document.getElementsByTagName('head').item(0).appendChild(style);
const el = document.createElement('div');
el.innerHTML = `<div id="app" class="app-wrapper"></div>`;
el.style.backgroundColor = 'transparent';
el.style.border = 'none';
document.body.append(el);
el.popover = 'manual';
el.showPopover();
const BTable = {
template: `
<table cellspacing="0" cellpadding="0">
<tr v-for="(row, rowIndex) in rows">
<td v-for="cell in row" :rowspan="cell.rowspan" :colspan="cell.colspan" :width="cell.width" :class="cell.class">
<slot :cell="cell">{{cell.value}}</slot>
</td>
</tr>
</table>
`,
props: {
rowCount: Number,
columns: Array, // [{ key: "", label: "", width: "100px", unit: "", editable: false }]
cells: Array // [{ row: 0, col: 0, rowspan: 1, colspan: 1, value: "", useColumnLabel: false }]
},
setup(props) {
const data = Vue.reactive({
rows: Vue.computed(() => {
const arr1 = [];
for (let i = 0; i < props.rowCount; i++) {
const arr2 = [];
for (let j = 0; j < props.columns.length; j++) {
const column = props.columns[j];
const cell = props.cells.find(x => x.row === i && x.col === j);
if (cell) {
const colspan = cell.colspan ?? 1;
arr2.push({
...cell,
rowspan: cell.rowspan ?? 1,
colspan: colspan,
value: cell.useColumnLabel ? column.label : cell.value,
width: colspan > 1 ? undefined : column.width,
column: column
});
}
}
arr1.push(arr2);
}
return arr1;
})
});
return data;
}
};
const app = Vue.createApp({
template: `
<n-dialog-provider>
<n-message-provider>
<n-button v-if="!showDrawer" class="btn-toggle" type="primary" round @click="showDrawer=true">
<template #icon>⇆</template>
</n-button>
<n-drawer v-model:show="showDrawer" display-directive="show" resizable class="drawer-wrapper">
<com @closeDrawer="showDrawer=false"/>
</n-drawer>
</n-message-provider>
</n-dialog-provider>
`,
setup() {
const data = Vue.reactive({
showDrawer: false
});
return data;
}
});
app.use(naive);
app.component('b-table', BTable);
app.component('com', com);
app.mount('#app');
};
//#region 扩展
Object.typedAssign = Object.assign;
Object.typedKeys = Object.keys;
Object.toArray = obj => {
const keys = Object.keys(obj);
return keys.map(x => ({ key: x, value: obj[x] }));
};
Object.deepClone = function (target) {
if (typeof target !== 'object' || target === null) return target;
if (target instanceof Date) {
return new Date(target.getTime());
}
if (target instanceof RegExp) {
return new RegExp(target);
}
if (target instanceof Array) {
return target.map(x => Object.deepClone(x));
}
// 对象
const newObj = Object.create(
Reflect.getPrototypeOf(target),
Object.getOwnPropertyDescriptors(target)
);
Reflect.ownKeys(target).forEach(key => {
newObj[key] = Object.deepClone(target[key]);
});
return newObj;
};
const compare = (item1, item2) =>
typeof item1 === 'string' && typeof item2 === 'string'
? item1.localeCompare(item2, 'zh')
: item1 > item2
? 1
: item2 > item1
? -1
: 0;
Array.prototype.flatTreeNode = function () {
const arr = [];
for (const node of this) {
arr.push(node);
if (node.children instanceof Array) {
arr.push(...node.children.flatTreeNode());
}
}
return arr;
};
Array.prototype.traverseTreeNode = function (callback) {
for (const node of this) {
callback(node);
if (node.children instanceof Array) {
node.children.traverseTreeNode(callback);
}
}
};
Array.prototype.findTreeNodePath = function (match) {
for (const node of this) {
if (match(node)) {
return [node];
}
if (node.children instanceof Array) {
const result = node.children.findTreeNodePath(match);
if (result) {
return [node, ...result];
}
}
}
return undefined;
};
Array.prototype.localSort = function () {
return this.sort(compare);
};
Array.prototype.sortBy = function (predicate) {
return this.sort((a, b) => compare(predicate(a), predicate(b)));
};
Array.prototype.sortByDescending = function (predicate) {
return this.sort((a, b) => -compare(predicate(a), predicate(b)));
};
Array.prototype.orderBy = function (predicate) {
return [...this].sort((a, b) => compare(predicate(a), predicate(b)));
};
Array.prototype.orderByDescending = function (predicate) {
return [...this].sort((a, b) => -compare(predicate(a), predicate(b)));
};
Array.prototype.orderByMany = function (predicates) {
return [...this].sort((a, b) => {
for (const predicate of predicates) {
const result = compare(predicate(a), predicate(b));
if (result) {
return result;
}
}
return 0;
});
};
Array.prototype.orderByManyDescending = function (predicates) {
return [...this].sort((a, b) => {
for (const predicate of predicates) {
const result = -compare(predicate(a), predicate(b));
if (result) {
return result;
}
}
return 0;
});
};
Array.prototype.first = function (predicate) {
const arr = predicate === undefined ? this : this.filter(predicate);
return arr[0];
};
Array.prototype.firstOrDefault = function (predicate) {
const arr = predicate === undefined ? this : this.filter(predicate);
return arr.length === 0 ? undefined : arr[0];
};
Array.prototype.groupBy = function (predicate) {
const obj = this.reduce((acc, obj) => {
const key = predicate(obj) ?? '';
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(obj);
return acc;
}, {});
return Object.typedKeys(obj).map(x => ({
key: x,
items: obj[x]
}));
};
Array.prototype.clear = function () {
this.length = 0;
};
Array.prototype.remove = function (item) {
for (let i = this.length - 1; i >= 0; i--) {
if (this[i] === item) {
this.splice(i, 1);
}
}
};
Array.prototype.removeRange = function (items) {
for (let i = this.length - 1; i >= 0; i--) {
if (items.indexOf(this[i]) >= 0) {
this.splice(i, 1);
}
}
};
Array.prototype.unique = function () {
const hash = [];
for (let i = 0; i < this.length; i++) {
let isOk = true;
for (let j = 0; j < i; j++) {
if (this[i] === this[j]) {
isOk = false;
break;
}
}
if (isOk) {
hash.push(this[i]);
}
}
return hash;
};
Array.prototype.sum = function (deep) {
let total = 0;
for (const item of this) {
if (typeof item === 'number') {
total += item;
} else if (deep && item instanceof Array) {
total += item.sum(true);
}
}
return total;
};
Array.prototype.average = function () {
let total = 0;
let k = 0;
for (const item of this) {
if (typeof item === 'number') {
total += item;
k++;
}
}
return k === 0 ? undefined : total / k;
};
Array.prototype.swap = function (oldIndex, newIndex) {
this.splice(newIndex, 0, this.splice(oldIndex, 1)[0]);
return this;
};
Array.prototype.max = function (predicate) {
return this.length === 0
? undefined
: predicate === undefined
? this.reduce((max, current) => {
return current > max ? current : max;
})
: this.reduce((max, current) => {
return predicate(current) > predicate(max) ? current : max;
});
};
Array.prototype.min = function (predicate) {
return this.length === 0
? undefined
: predicate === undefined
? this.reduce((min, current) => {
return current < min ? current : min;
})
: this.reduce((min, current) => {
return predicate(current) < predicate(min) ? current : min;
});
};
Array.prototype.mapObject = function (mapKey, mapValue) {
return Object.fromEntries(this.map((el, i, arr) => [mapKey(el, i, arr), mapValue(el, i, arr)]));
};
Number.prototype.angleToRadian = function () {
const value = Number(this);
return (value * Math.PI) / 180;
};
Number.prototype.radianToAngle = function () {
const value = Number(this);
return (180 * value) / Math.PI;
};
Number.prototype.fillZero = function (length) {
const value = Number(this);
return Number.isInteger(value) && value.toString().length < length
? ('0'.repeat(length) + value).slice(-length)
: value.toString();
};
Number.prototype.toThousands = function (unit, withSpaceBetween = true, prepend) {
return this.toString().toThousands(unit, withSpaceBetween, prepend);
};
Number.prototype.toPercentage = function (fractionDigits) {
const value = Number(this);
return `${(value * 100).toFixed(fractionDigits)}%`;
};
Number.prototype.simplify = function (chinese, fractionDigits = 2) {
const value = Number(this);
const units = chinese ? ['万', '亿'] : ['million', 'billion'];
const divisors = chinese ? [10_000, 100_000_000] : [1_000_000, 1_000_000_000];
const index = value < divisors[1] ? 0 : 1;
const num = (value / divisors[index]).toFixed(fractionDigits);
const result = Number(num);
return result === 0 ? '0' : result + ' ' + units[index];
};
Number.prototype.accurate = function (precision = 2) {
const value = Number(this);
if (precision >= 0) {
return Number(value.toFixed(precision));
}
const num = Math.pow(10, precision);
return Number((value * num).toFixed(0)) / num;
};
Number.prototype.toPageCount = function (pageSize) {
const value = Number(this);
return Math.floor(Math.abs(value - 1) / pageSize) + 1;
};
String.prototype.replaceAll = function (find, replace) {
return this.replace(new RegExp(find, 'g'), replace);
};
String.prototype.equals = function (value, ignoreCase = true) {
const txt = value ?? '';
return ignoreCase ? this.toLowerCase() === txt.toLowerCase() : this === txt;
};
String.prototype.toThousands = function (unit, withSpaceBetween = true, prepend) {
const value = this;
const index = value.indexOf('.');
const firstPart = index >= 0 ? value.substring(0, index) : value;
const lastPart = index >= 0 ? value.substring(index) : '';
const result = firstPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',') + lastPart;
return unit
? prepend
? withSpaceBetween
? `${unit} ${result}`
: unit + result
: withSpaceBetween
? `${result} ${unit}`
: result + unit
: result;
};
//#endregion