improve UIUX
This commit is contained in:
18
README.md
18
README.md
@@ -422,4 +422,20 @@ watch(loading, (load) => {
|
|||||||
load ? spinner.value?.open() : spinner.value?.close();
|
load ? spinner.value?.open() : spinner.value?.close();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### 关于 tooltip
|
||||||
|
|
||||||
|
kuc 没有实现插槽,所以应该当成一个普通组件使用:
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<button ref="buyButton">购买</button>
|
||||||
|
<kuc-tooltip title="点击购买" :container="buyButton"></kuc-tooltip>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const buyButton = shallowRef<HTMLButtonElement | null>(null);
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|||||||
1
components.d.ts
vendored
1
components.d.ts
vendored
@@ -8,6 +8,7 @@ export {}
|
|||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
Config: typeof import('./src/components/Config.vue')['default']
|
Config: typeof import('./src/components/Config.vue')['default']
|
||||||
|
LicenseStatus: typeof import('./src/components/LicenseStatus.vue')['default']
|
||||||
PluginInput: typeof import('./src/components/basic/PluginInput.vue')['default']
|
PluginInput: typeof import('./src/components/basic/PluginInput.vue')['default']
|
||||||
PluginLabel: typeof import('./src/components/basic/PluginLabel.vue')['default']
|
PluginLabel: typeof import('./src/components/basic/PluginLabel.vue')['default']
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<!-- 许可证状态信息 -->
|
||||||
|
<LicenseStatus />
|
||||||
|
|
||||||
<h2 class="settings-heading">{{ $t('config.title') }}</h2>
|
<h2 class="settings-heading">{{ $t('config.title') }}</h2>
|
||||||
<p class="kintoneplugin-desc">{{ $t('config.desc') }}</p>
|
<p class="kintoneplugin-desc">{{ $t('config.desc') }}</p>
|
||||||
|
|
||||||
@@ -9,7 +12,7 @@
|
|||||||
|
|
||||||
<div class="action-area">
|
<div class="action-area">
|
||||||
<kuc-button text="キャンセル" type="normal" @click="cancel" />
|
<kuc-button text="キャンセル" type="normal" @click="cancel" />
|
||||||
<kuc-button :disabled="loading" text="保存する" class="save-btn" type="submit" @click="save" />
|
<kuc-button text="保存する" class="save-btn" type="submit" @click="save" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 必须使用 v-show 让 spinner dom 创建的时候不显示 -->
|
<!-- 必须使用 v-show 让 spinner dom 创建的时候不显示 -->
|
||||||
@@ -19,10 +22,8 @@
|
|||||||
import type { Setting } from '@/types';
|
import type { Setting } from '@/types';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useKintoneClient } from '@/composables/useKintoneClient';
|
import { useKintoneClient } from '@/composables/useKintoneClient';
|
||||||
import { useLicenseManager } from '@/composables/useLicenseManager';
|
|
||||||
import type { Spinner } from 'kintone-ui-component';
|
import type { Spinner } from 'kintone-ui-component';
|
||||||
import LicenseModal from '@/components/LicenseModal.vue';
|
import LicenseStatus from './LicenseStatus.vue';
|
||||||
import LicenseNotification from '@/components/LicenseNotification.vue';
|
|
||||||
|
|
||||||
import { nextTick, onMounted, reactive, ref, shallowRef, watch } from 'vue';
|
import { nextTick, onMounted, reactive, ref, shallowRef, watch } from 'vue';
|
||||||
|
|
||||||
@@ -44,21 +45,11 @@ const loading = ref(false);
|
|||||||
const mainArea = shallowRef<HTMLElement | null>(null);
|
const mainArea = shallowRef<HTMLElement | null>(null);
|
||||||
const spinner = shallowRef<Spinner | null>(null);
|
const spinner = shallowRef<Spinner | null>(null);
|
||||||
|
|
||||||
const licenseManager = useLicenseManager();
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
// 等待页面完全渲染后再显示加载状态,实现更平滑的用户体验
|
// 等待页面完全渲染后再显示加载状态,实现更平滑的用户体验
|
||||||
nextTick(async () => {
|
nextTick(async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
|
||||||
// 检查许可证
|
|
||||||
if (!licenseManager.canAccessFeatures()) {
|
|
||||||
// 没有权限或许可证无效,显示弹框或错误提示
|
|
||||||
showLicenseError();
|
|
||||||
loading.value = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取已保存的插件配置
|
// 获取已保存的插件配置
|
||||||
const savedSetting = kintone.plugin.app.getConfig(props.pluginId);
|
const savedSetting = kintone.plugin.app.getConfig(props.pluginId);
|
||||||
setting.buttonName = savedSetting?.buttonName || $t('config.button.default');
|
setting.buttonName = savedSetting?.buttonName || $t('config.button.default');
|
||||||
@@ -70,10 +61,8 @@ onMounted(async () => {
|
|||||||
console.log('pluginsInfo', pluginsInfo);
|
console.log('pluginsInfo', pluginsInfo);
|
||||||
// 模拟加载时间,展示 spinner 效果
|
// 模拟加载时间,展示 spinner 效果
|
||||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||||
loading.value = false;
|
|
||||||
|
|
||||||
// 检查许可证状态,显示相关信息
|
loading.value = false;
|
||||||
checkLicenseStatus();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -115,54 +104,6 @@ async function save() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 显示许可证错误
|
|
||||||
*/
|
|
||||||
function showLicenseError() {
|
|
||||||
// 添加许可证状态显示区域
|
|
||||||
const licenseStatusElement = document.createElement('div');
|
|
||||||
licenseStatusElement.className = 'license-status';
|
|
||||||
licenseStatusElement.innerHTML = `
|
|
||||||
<div class="license-error">
|
|
||||||
<h3>许可证无效</h3>
|
|
||||||
<p>您的插件许可证已过期或无效,请联系管理员或购买许可证。</p>
|
|
||||||
<button class="license-refresh-btn" onclick="window.location.reload()">重新检查</button>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
// 插入到页面顶部
|
|
||||||
const mainArea = document.getElementById('main-area');
|
|
||||||
if (mainArea && mainArea.parentNode) {
|
|
||||||
mainArea.parentNode.insertBefore(licenseStatusElement, mainArea);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查许可证状态并显示相关信息
|
|
||||||
*/
|
|
||||||
function checkLicenseStatus() {
|
|
||||||
const licenseInfo = licenseManager.getLicenseDisplayInfo();
|
|
||||||
|
|
||||||
if (licenseInfo) {
|
|
||||||
// 添加许可证状态显示
|
|
||||||
const statusElement = document.createElement('div');
|
|
||||||
statusElement.className = 'license-status-info';
|
|
||||||
statusElement.innerHTML = `
|
|
||||||
<div class="license-info">
|
|
||||||
<h4>许可证状态</h4>
|
|
||||||
<p>到期时间: ${licenseInfo.expiryDate}</p>
|
|
||||||
<p>状态: ${licenseInfo.isExpired ? '已过期' : licenseInfo.remainingDays === Infinity ? '永久' : `剩余 ${licenseInfo.remainingDays} 天`}</p>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
// 插入到设置区域上方
|
|
||||||
const mainArea = document.getElementById('main-area');
|
|
||||||
if (mainArea && mainArea.parentNode) {
|
|
||||||
mainArea.parentNode.insertBefore(statusElement, mainArea);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取消操作并返回插件列表
|
* 取消操作并返回插件列表
|
||||||
* 重定向到插件管理页面
|
* 重定向到插件管理页面
|
||||||
|
|||||||
151
src/components/LicenseStatus.vue
Normal file
151
src/components/LicenseStatus.vue
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="shown" class="license-status-info">
|
||||||
|
<div class="license-content">
|
||||||
|
<div class="license-status-text">
|
||||||
|
<strong>许可证状态: </strong>
|
||||||
|
<span v-if="licenseDisplayInfo" v-html="licenseStatusText"></span><span v-else> ... </span>
|
||||||
|
</div>
|
||||||
|
<div class="license-actions">
|
||||||
|
<template v-if="!licenseDisplayInfo.isPaid">
|
||||||
|
<button class="action-btn" @click="refreshLicenseStatus" :disabled="checking" ref="checkButton">检查</button>
|
||||||
|
<kuc-tooltip title="重新检查许可证状态" :container="checkButton"></kuc-tooltip>
|
||||||
|
<button class="action-btn main" @click="purchaseLicense" ref="buyButton">购买</button>
|
||||||
|
<kuc-tooltip title="购买后当前域名下所有应用都可使用" :container="buyButton"></kuc-tooltip>
|
||||||
|
</template>
|
||||||
|
<button v-else class="action-btn" @click="hidePaidMsg">不再显示</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, computed, shallowRef } from 'vue';
|
||||||
|
import { LicenseService } from '@/services/LicenseService';
|
||||||
|
import type { LicenseInfo, LicenseCheckResult } from '@/types/license';
|
||||||
|
import { LicenseStorage } from '@/utils/LicenseStorage';
|
||||||
|
|
||||||
|
type LicenseDisplayInfo = {
|
||||||
|
isPaid: boolean;
|
||||||
|
expiryDate: string;
|
||||||
|
isExpired: boolean;
|
||||||
|
remainingDays: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 状态管理
|
||||||
|
const licenseInfo = ref<LicenseInfo | undefined>();
|
||||||
|
const loading = ref(true);
|
||||||
|
const shown = ref(false);
|
||||||
|
const checking = ref(false);
|
||||||
|
const checkButton = shallowRef<HTMLButtonElement | null>(null);
|
||||||
|
const buyButton = shallowRef<HTMLButtonElement | null>(null);
|
||||||
|
|
||||||
|
// 许可证显示信息
|
||||||
|
const licenseDisplayInfo = computed<LicenseDisplayInfo>(() => {
|
||||||
|
if (!licenseInfo.value || loading.value) {
|
||||||
|
return {
|
||||||
|
isPaid: false,
|
||||||
|
expiryDate: '未知',
|
||||||
|
isExpired: false,
|
||||||
|
remainingDays: 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isPaid: licenseInfo.value.isPaid,
|
||||||
|
expiryDate: LicenseService.formatExpiryDate(licenseInfo.value.expiredTime),
|
||||||
|
isExpired: licenseInfo.value.expiredTime < Date.now() && !licenseInfo.value.isPaid,
|
||||||
|
remainingDays: LicenseService.getDaysRemaining(licenseInfo.value.expiredTime),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const result = await LicenseService.checkLicense();
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||||
|
licenseInfo.value = result.license;
|
||||||
|
|
||||||
|
shown.value = isPaidAreaShown();
|
||||||
|
if (!shown.value) {
|
||||||
|
addPaidLabel();
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
const addPaidLabel = () => {
|
||||||
|
const isExist = !!document.querySelector('#license-label')
|
||||||
|
if (!shown.value && !isExist) {
|
||||||
|
const spanElement = document.createElement('span');
|
||||||
|
spanElement.textContent = '已授权';
|
||||||
|
spanElement.id = 'license-label';
|
||||||
|
document.querySelector('#app > .settings-heading')?.appendChild(spanElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isPaidAreaShown = () => {
|
||||||
|
if (!licenseInfo.value?.isPaid) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const settings = LicenseStorage.getSettings(licenseInfo.value.pluginId);
|
||||||
|
if (settings.hideLicenseAreaIfPaid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const licenseStatusText = computed(() => {
|
||||||
|
if (!licenseDisplayInfo.value) {
|
||||||
|
return '未知';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loading.value) {
|
||||||
|
return '加载中...';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (licenseDisplayInfo.value.isPaid) {
|
||||||
|
return '<span class="text-green">永久可用</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
let status = `到期时间 ${licenseDisplayInfo.value.expiryDate} `;
|
||||||
|
|
||||||
|
if (licenseDisplayInfo.value.isExpired) {
|
||||||
|
status += '(<span class="text-red">已过期</span>)';
|
||||||
|
} else if (licenseDisplayInfo.value.remainingDays == 0) {
|
||||||
|
status += '(今天)';
|
||||||
|
} else if (licenseDisplayInfo.value.remainingDays == 1) {
|
||||||
|
status += '(明天)';
|
||||||
|
} else {
|
||||||
|
status += '(剩余 ' + licenseDisplayInfo.value.remainingDays + ' 天)';
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
});
|
||||||
|
|
||||||
|
async function refreshLicenseStatus() {
|
||||||
|
checking.value = true;
|
||||||
|
loading.value = true;
|
||||||
|
// 模拟加载时间,展示 spinner 效果
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||||
|
|
||||||
|
const result = await LicenseService.forceRefreshLicense();
|
||||||
|
licenseInfo.value = result.license;
|
||||||
|
loading.value = false;
|
||||||
|
checking.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function purchaseLicense() {
|
||||||
|
alert(
|
||||||
|
`请联系管理员或访问官方网站购买许可证。\nDomain: ${licenseInfo.value?.domain}\nPlugin: ${licenseInfo.value?.pluginId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hidePaidMsg() {
|
||||||
|
const pluginId = licenseInfo.value?.pluginId;
|
||||||
|
if (!pluginId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const settings = LicenseStorage.getSettings(pluginId);
|
||||||
|
settings.hideLicenseAreaIfPaid = true;
|
||||||
|
LicenseStorage.saveSetting(settings, pluginId);
|
||||||
|
shown.value = false;
|
||||||
|
addPaidLabel();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
/* 最上面的说明 */
|
/* 最上面的说明 */
|
||||||
.settings-heading {
|
.settings-heading {
|
||||||
padding: 1em 0;
|
padding: 1em 0;
|
||||||
margin-bottom: 8px;
|
margin: 8px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* label 样式 */
|
/* label 样式 */
|
||||||
|
|||||||
@@ -271,27 +271,99 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.license-status-info {
|
.license-status-info {
|
||||||
margin-bottom: 20px;
|
padding: 12px 16px;
|
||||||
padding: 16px;
|
margin-right: 24px;
|
||||||
border-radius: 6px;
|
border-radius: 4px;
|
||||||
border: 1px solid #e5e5e5;
|
border: 1px solid #ddd;
|
||||||
background-color: #f7fafc;
|
background-color: #f9f9f9;
|
||||||
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.license-status-info .license-info h4 {
|
.license-status-info .license-content {
|
||||||
margin: 0 0 12px 0;
|
display: flex;
|
||||||
color: #2d3748;
|
justify-content: space-between;
|
||||||
font-size: 16px;
|
align-items: baseline;
|
||||||
font-weight: 600;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.license-status-info .license-info p {
|
.license-status-info .license-status-text {
|
||||||
margin: 0 0 8px 0;
|
color: #333;
|
||||||
font-size: 14px;
|
flex: 1;
|
||||||
color: #4a5568;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.license-status-info .license-info p:last-child {
|
.license-status-info .license-actions {
|
||||||
margin-bottom: 0;
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.license-status-info .action-btn {
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
min-width: 65px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.license-status-info .action-btn:not(.main) {
|
||||||
|
background: transparent;
|
||||||
|
color: #666;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.license-status-info .action-btn:not(.main):disabled {
|
||||||
|
background: #efefef;
|
||||||
|
color: #a0a0a0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.license-status-info .action-btn:not(.main):not(:disabled):hover {
|
||||||
|
background: #eee;
|
||||||
|
border-color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.license-status-info .action-btn:not(.main):not(:disabled):active {
|
||||||
|
background: #BDBDBD;
|
||||||
|
border-color: #757575;
|
||||||
|
}
|
||||||
|
|
||||||
|
.license-status-info .action-btn.main {
|
||||||
|
background: #4CAF50;
|
||||||
|
color: white;
|
||||||
|
border: 1px solid #4CAF50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.license-status-info .action-btn.main:hover {
|
||||||
|
background: #388E3C;
|
||||||
|
border-color: #388E3C;
|
||||||
|
}
|
||||||
|
|
||||||
|
.license-status-info .action-btn.main:active {
|
||||||
|
background: #33691E;
|
||||||
|
border-color: #33691E;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-link {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-link:hover {
|
||||||
|
color: #daf0ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-red {
|
||||||
|
color: #B71C1C;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-green {
|
||||||
|
color: #4CAF50;
|
||||||
|
}
|
||||||
|
|
||||||
|
#license-label {
|
||||||
|
background-color: #4CAF50;
|
||||||
|
color: white;
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-radius: 9999px;
|
||||||
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { MobileNotification } from 'kintone-ui-component/lib/mobile/notification
|
|||||||
export class LicenseService {
|
export class LicenseService {
|
||||||
// 常量定义
|
// 常量定义
|
||||||
private static readonly WARNING_DAYS_BEFORE_EXPIRY = 7;
|
private static readonly WARNING_DAYS_BEFORE_EXPIRY = 7;
|
||||||
private static readonly TRIAL_DATE = 1;
|
private static readonly TRIAL_DATE = 30;
|
||||||
private static PLUGIN_ID: string = '';
|
private static PLUGIN_ID: string = '';
|
||||||
// ============ 基础工具函数 ============
|
// ============ 基础工具函数 ============
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ export class LicenseService {
|
|||||||
* 获取插件ID
|
* 获取插件ID
|
||||||
*/
|
*/
|
||||||
static getPluginId(): string {
|
static getPluginId(): string {
|
||||||
return this.PLUGIN_ID;
|
return this.PLUGIN_ID || new URLSearchParams(window.location.search).get('pluginId') || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,7 +122,7 @@ export class LicenseService {
|
|||||||
*/
|
*/
|
||||||
static formatExpiryDate(timestamp: number): string {
|
static formatExpiryDate(timestamp: number): string {
|
||||||
if (timestamp === -1) return '永久';
|
if (timestamp === -1) return '永久';
|
||||||
return new Date(timestamp).toLocaleDateString('zh-CN');
|
return new Date(timestamp).toLocaleDateString(kintone.getLoginUser().language);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -132,7 +132,7 @@ export class LicenseService {
|
|||||||
if (timestamp === -1) return Infinity;
|
if (timestamp === -1) return Infinity;
|
||||||
const now = new Date().getTime();
|
const now = new Date().getTime();
|
||||||
const remainingMs = timestamp - now;
|
const remainingMs = timestamp - now;
|
||||||
return Math.ceil(remainingMs / (24 * 60 * 60 * 1000));
|
return Math.floor(remainingMs / (24 * 60 * 60 * 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -167,28 +167,32 @@ export class LicenseService {
|
|||||||
warningDialogMessage?: string;
|
warningDialogMessage?: string;
|
||||||
}) {
|
}) {
|
||||||
const remainingDays = this.getDaysRemaining(license.expiredTime);
|
const remainingDays = this.getDaysRemaining(license.expiredTime);
|
||||||
const msg = remainingDays > 0 ? ` ${remainingDays} 天后` : '今天'
|
if (remainingDays <= 0) {
|
||||||
const defaultMessage = `您的插件许可证将在${msg}到期,请及时续期以避免服务中断。`;
|
return
|
||||||
|
}
|
||||||
|
const msg = remainingDays > 1 ? ` ${remainingDays} 天后` : (remainingDays > 0 ? '明天' : '今天')
|
||||||
|
const link = `https://alicorn.cybozu.com/k/admin/app/${kintone.app.getId()}/plugin/config?pluginId=${this.getPluginId()}`
|
||||||
|
const defaultMessage = `您的插件将在${msg}试用结束<br>如需使用请进入<a class="notification-link" href="${link}">「プラグインの設定」</a>查看详情。`;
|
||||||
|
|
||||||
// 使用自定义消息或默认消息
|
// 使用自定义消息或默认消息
|
||||||
const message = options?.warningDialogMessage || defaultMessage;
|
const message = options?.warningDialogMessage || defaultMessage;
|
||||||
|
|
||||||
// 检查是否已设置不再提醒
|
// 检查是否已设置不再提醒
|
||||||
const settings = LicenseStorage.getSettings(this.getPluginId());
|
// const settings = LicenseStorage.getSettings(this.getPluginId());
|
||||||
if (settings.suppressMsgTime && this.isToday(settings.suppressMsgTime)) {
|
// if (settings.suppressMsgTime && this.isToday(settings.suppressMsgTime)) {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
delete settings.suppressMsgTime
|
// delete settings.suppressMsgTime
|
||||||
LicenseStorage.saveSetting(settings, this.getPluginId());
|
// LicenseStorage.saveSetting(settings, this.getPluginId());
|
||||||
|
|
||||||
if (await kintone.isMobilePage()) {
|
if (await kintone.isMobilePage()) {
|
||||||
const notification = new MobileNotification({
|
const notification = new MobileNotification({
|
||||||
text: message,
|
content: message,
|
||||||
});
|
});
|
||||||
notification.open();
|
notification.open();
|
||||||
} else {
|
} else {
|
||||||
const notification = new Notification({
|
const notification = new Notification({
|
||||||
text: message,
|
content: message,
|
||||||
type: 'info',
|
type: 'info',
|
||||||
});
|
});
|
||||||
notification.open();
|
notification.open();
|
||||||
@@ -279,6 +283,7 @@ export class LicenseService {
|
|||||||
private static mockCreateTrialLicense(): LicenseInfo {
|
private static mockCreateTrialLicense(): LicenseInfo {
|
||||||
const expiryDate = new Date();
|
const expiryDate = new Date();
|
||||||
expiryDate.setDate(expiryDate.getDate() + this.TRIAL_DATE);
|
expiryDate.setDate(expiryDate.getDate() + this.TRIAL_DATE);
|
||||||
|
expiryDate.setHours(23, 59, 59, 999);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
expiredTime: expiryDate.getTime(),
|
expiredTime: expiryDate.getTime(),
|
||||||
|
|||||||
1
src/types/license.d.ts
vendored
1
src/types/license.d.ts
vendored
@@ -17,6 +17,7 @@ export interface LicenseInfo {
|
|||||||
|
|
||||||
export interface LicenseSetting {
|
export interface LicenseSetting {
|
||||||
suppressMsgTime?: number;
|
suppressMsgTime?: number;
|
||||||
|
hideLicenseAreaIfPaid?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LicenseCheckResult {
|
export interface LicenseCheckResult {
|
||||||
|
|||||||
Reference in New Issue
Block a user