Merge branch 'StableVersion' of ssh://18.167.251.121:10002/aidlab/aida_front into StableVersion

This commit is contained in:
2026-01-15 10:47:57 +08:00
56 changed files with 3384 additions and 1719 deletions

View File

@@ -17,7 +17,8 @@
<div class="generalModel_btn">
<div class="generalModel_closeIcon" @click.stop="cancelDsign()">
<svg
width="100%" height="100%"
width="100%"
height="100%"
viewBox="0 0 46 46"
fill="none"
xmlns="http://www.w3.org/2000/svg"
@@ -49,7 +50,10 @@
</div>
<div class="allUserPoeration_center admin_page">
<div class="admin_state_item">
<span>{{ $t('admin.UserName') }}: <span>*</span></span>
<span>
{{ $t('admin.UserName') }}:
<span>*</span>
</span>
<input
v-model="userName"
:placeholder="$t('admin.enterUserName')"
@@ -58,7 +62,10 @@
/>
</div>
<div class="admin_state_item">
<span>{{ $t('admin.UserEmail') }}: <span>*</span></span>
<span>
{{ $t('admin.UserEmail') }}:
<span>*</span>
</span>
<input
v-model="userEmail"
:placeholder="$t('admin.enterEmail')"
@@ -67,7 +74,10 @@
/>
</div>
<div class="admin_state_item">
<span>{{ $t('admin.Password') }}: <span>*</span></span>
<span>
{{ $t('admin.Password') }}:
<span>*</span>
</span>
<input
@focus="focus"
@blur="blur"
@@ -86,6 +96,19 @@
style="width: 250px"
/>
</div>
<div class="admin_state_item" v-if="title?.value == 'Edit'">
<span>
{{ $t('admin.SubscribePlan') }}:
<span>*</span>
</span>
<a-select
v-model:value="subscriptionPlanId"
style="width: 250px"
:options="activePlanOptions"
:field-names="{ label: 'name', value: 'id' }"
:placeholder="$t('admin.SelectPlan')"
></a-select>
</div>
</div>
<div class="allUserPoeration_btn admin_page">
<div class="admin_search_item" @click="cancelDsign">{{ $t('admin.Close') }}</div>
@@ -96,7 +119,7 @@
<a-spin size="large" />
</div>
</template>
<script>
<script lang="ts">
import {
defineComponent,
ref,
@@ -105,90 +128,114 @@ import {
onMounted,
nextTick,
toRefs,
} from "vue";
import { Https } from "@/tool/https";
import { Modal, message } from "ant-design-vue";
import { ExclamationCircleOutlined } from "@ant-design/icons-vue";
import { formatTime, isEmail } from "@/tool/util";
import md5 from "md5";
computed
} from 'vue'
import { Https } from '@/tool/https'
import { Modal, message } from 'ant-design-vue'
import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
import { formatTime, isEmail } from '@/tool/util'
import md5 from 'md5'
import { useI18n } from 'vue-i18n'
export default defineComponent({
components: {},
emits: ["searchHistoryList"],
props: {
planOptions: {
type: Array,
default: () => []
}
},
emits: ['searchHistoryList'],
setup(props, { emit }) {
const {t} = useI18n()
const { t } = useI18n()
const { planOptions } = toRefs(props)
// 筛选出状态为 ACTIVE 的订阅计划
const activePlanOptions = computed(() => {
if (!planOptions.value || !Array.isArray(planOptions.value)) {
return []
}
return planOptions.value.filter((plan: any) => plan.status === 'ACTIVE')
})
let operations = reactive({
operationsModal: false,
operationsEdit: false,
loadingShow: false,
title: null,
});
title: null
})
let operationsData = reactive({
accountId: -1,
userName: "",
userEmail: "",
password: "",
oldPassword: "",
credits: "",
});
userName: '',
userEmail: '',
password: '',
oldPassword: '',
credits: '',
subscriptionPlanId: '',
oldSubscriptionPlanId: ''
})
let state = ref([
{
label: "visitor",
value: "0",
label: 'visitor',
value: '0'
},
{
label: "yearly",
value: "1",
label: 'yearly',
value: '1'
},
{
label: "monthly",
value: "2",
label: 'monthly',
value: '2'
},
{
label: "trial",
value: "3",
},
]);
label: 'trial',
value: '3'
}
])
let init = (funStr, data) => {
operations.operationsModal = true;
operations.operationsEdit = true;
operations.title = funStr;
if (funStr.value == "Add") operations.operationsEdit = false;
if (funStr.value == "Edit") {
operationsData.accountId = data.id;
operationsData.userName = data.userName;
operationsData.userEmail = data.userEmail;
operationsData.password = data.userPassword?data.userPassword:null;
operationsData.oldPassword = data.userPassword;
operations.operationsModal = true
operations.operationsEdit = true
operations.title = funStr
if (funStr.value == 'Add') operations.operationsEdit = false
if (funStr.value == 'Edit') {
operationsData.accountId = data.id
operationsData.userName = data.userName
operationsData.userEmail = data.userEmail
operationsData.password = data.userPassword ? data.userPassword : null
operationsData.oldPassword = data.userPassword
// operationsData.validStartTime='2024-08-05T00:00:06'
// operationsData.validEndTime='2024-08-05T00:00:06'
operationsData.credits = data.creditsUsageLimit;
operationsData.credits = data.creditsUsageLimit
operationsData.subscriptionPlanId = data.subscriptionPlanId || ''
operationsData.oldSubscriptionPlanId = data.subscriptionPlanId || ''
// operationsData.accountId = data.accountId
// operationsData.userName = data.userName
// operationsData.userEmail = data.userEmail
// operationsData.validStartTime = formatTime(data.validStartTime)
// operationsData.validEndTime = formatTime(data.validEndTime)
}
};
let focus = (event) => {
if (funStr.value == 'Add') {
operationsData.subscriptionPlanId = ''
operationsData.oldSubscriptionPlanId = ''
}
}
let focus = event => {
if (operationsData.password == operationsData.oldPassword) {
operationsData.password = "";
operationsData.password = ''
}
};
let blur = (event) => {
console.log(operationsData.password == "" && operationsData.oldPassword);
if (operationsData.password == "" && operationsData.oldPassword) {
operationsData.password = operationsData.oldPassword;
}
let blur = event => {
console.log(operationsData.password == '' && operationsData.oldPassword)
if (operationsData.password == '' && operationsData.oldPassword) {
operationsData.password = operationsData.oldPassword
}
};
}
let setAddData = () => {
return {
creditsUsageLimit: operationsData.credits,
userEmail: operationsData.userEmail,
userPassword: operationsData.password?md5(operationsData.password + "abc"):'',
userPassword: operationsData.password ? md5(operationsData.password + 'abc') : '',
userName: operationsData.userName,
};
};
subscriptionPlanId: operationsData.subscriptionPlanId
}
}
let setEditData = () => {
return {
id: operationsData.accountId,
@@ -198,57 +245,63 @@ export default defineComponent({
userPassword:
operationsData.password == operationsData.oldPassword
? null
: md5(operationsData.password + "abc"),
};
};
let cancelDsign = () => {
operationsData.accountId = -1;
operationsData.userName = "";
operationsData.userEmail = "";
operationsData.password = "";
operationsData.credits = "";
operations.operationsModal = false;
};
let setOk = () => {
let data;
if (operations.title?.value == "Add") {
data = setAddData();
if (!isEmail(data.userEmail)) {
message.info(t('admin.jsContent1'));
return;
}
if (
!data.userName ||
!data.userEmail ||
!data.userPassword
)
return message.warning(t('admin.jsContent2'));
Https.axiosPost(Https.httpUrls.addOrUpdateSubAccount, data).then(
(rv) => {
if (rv) {
cancelDsign();
emit("searchHistoryList");
}
}
);
} else {
data = setEditData();
if (!isEmail(data.userEmail)) {
message.info("The email format is incorrect");
return;
}
if (!data.userName || !data.userEmail)
return message.warning("Please check the input box marked with *");
Https.axiosPost(Https.httpUrls.addOrUpdateSubAccount, data).then(
(rv) => {
if (rv) {
cancelDsign();
emit("searchHistoryList");
}
}
);
: md5(operationsData.password + 'abc'),
subscriptionPlanId: operationsData.subscriptionPlanId
}
};
}
let cancelDsign = () => {
operationsData.accountId = -1
operationsData.userName = ''
operationsData.userEmail = ''
operationsData.password = ''
operationsData.credits = ''
operationsData.subscriptionPlanId = ''
operationsData.oldSubscriptionPlanId = ''
operations.operationsModal = false
}
let setOk = () => {
let data
if (operations.title?.value == 'Add') {
data = setAddData()
if (!isEmail(data.userEmail)) {
message.info(t('admin.jsContent1'))
return
}
if (!data.userName || !data.userEmail || !data.userPassword)
return message.warning(t('admin.jsContent2'))
Https.axiosPost(Https.httpUrls.addOrUpdateSubAccount, data).then(rv => {
if (rv) {
cancelDsign()
emit('searchHistoryList')
}
})
} else {
data = setEditData()
if (!isEmail(data.userEmail)) {
message.info('The email format is incorrect')
return
}
if (!data.userName || !data.userEmail || !data.subscriptionPlanId)
return message.warning('Please check the input box marked with *')
const needSwitchPlan =
operationsData.subscriptionPlanId &&
operationsData.subscriptionPlanId !== operationsData.oldSubscriptionPlanId
Https.axiosPost(Https.httpUrls.addOrUpdateSubAccount, data).then(async rv => {
if (rv) {
if (needSwitchPlan) {
await Https.axiosGet(Https.httpUrls.switchSubAccountSubscribePlan, {
params: {
targetSubscriptionPlanId: operationsData.subscriptionPlanId,
subAccId: operationsData.accountId
}
})
}
cancelDsign()
emit('searchHistoryList')
}
})
}
}
return {
...toRefs(operations),
...toRefs(operationsData),
@@ -258,14 +311,16 @@ export default defineComponent({
focus,
blur,
setOk,
};
planOptions,
activePlanOptions
}
},
data() {
return {};
return {}
},
mounted() {},
methods: {},
});
methods: {}
})
</script>
<style lang="less" scoped>
:deep(.allUserPoeration_modal) {

View File

@@ -16,29 +16,6 @@
</template>
</a-range-picker>
</div>
<!-- <div class="admin_state_item">
<span>Country or Region:</span>
<a-select
v-model:value="country"
:allowClear="true"
show-search
style="width: 230px"
:filter-option="filterOption"
placeholder="Select Item..."
max-tag-count="responsive"
:options="allCountry"
></a-select>
</div> -->
<!-- <div class="admin_state_item">
<span>Email:</span>
<input
v-model="email"
placeholder="Please enter email"
@keydown.enter="gettrialList"
type="text"
style="width: 230px"
/>
</div> -->
<div class="admin_state_item">
<span>{{ $t('admin.UserName') }}:</span>
<a-select
@@ -53,19 +30,6 @@
@keydown.enter="gettrialList"
></a-select>
</div>
<!-- <div class="admin_state_item">
<span>User Type:</span>
<a-select
v-model:value="systemUser"
size="large"
style="width: 230px"
optionFilterProp="label"
:options="state"
placeholder="Please select"
allowClear
show-search
></a-select>
</div> -->
</div>
<div class="admin_search">
<div class="admin_search_item" @click="searchHistoryList">
@@ -116,6 +80,24 @@
</div>
</div>
<div class="admin_table_content" ref="historyTable">
<div class="admin_state_list plan_list">
<div
v-for="plan in planFilterOptions"
:key="plan.id"
class="plan_item"
:class="{
active: subscriptionPlanId === plan.id,
disabled: plan.status === 'PENDING'
}"
@click="plan.status !== 'PENDING' && selectPlanFilter(plan.id)"
>
<span class="plan_name">{{ plan.name }}</span>
<MoreOutlined
class="plan_more_icon"
@click.stop="plan.status !== 'PENDING' && openPlanRenameModal(plan)"
/>
</div>
</div>
<a-table
@resizeColumn="handleResizeColumn"
:loading="tableLoading"
@@ -147,12 +129,6 @@
<div class="operate_item" @click="deleteAagree(record)">
{{ $t('admin.Delete') }}
</div>
<!-- <div
class="operate_item"
@click="deleteGroup(record, index)"
>
Delete
</div> -->
</div>
</template>
</a-table>
@@ -160,7 +136,31 @@
<allUserPoerationsVue
ref="allUserPoerationsVue"
@searchHistoryList="searchHistoryList"
:plan-options="planFilterOptions"
></allUserPoerationsVue>
<div class="renamePlanModal" ref="renamePlanModal"></div>
<!-- 重命名订阅计划弹窗 -->
<a-modal
v-model:visible="renamePlanModalVisible"
:title="$t('admin.RenamePlan')"
@ok="confirmRenamePlan"
@cancel="cancelRenamePlan"
:ok-text="$t('admin.OK')"
:cancel-text="$t('admin.Cancel')"
:get-container="() => $refs.renamePlanModal"
>
<div class="rename-plan-form">
<div class="admin_state_item">
<span>{{ $t('admin.PlanName') }}:</span>
<a-input
v-model:value="renamePlanForm.planName"
:placeholder="$t('admin.InputPlanName')"
style="width: 250px"
@pressEnter="confirmRenamePlan"
/>
</div>
</div>
</a-modal>
</div>
</template>
<script lang="ts">
@@ -171,19 +171,23 @@ import {
computed,
reactive,
toRefs,
onMounted
unref,
watch
} from 'vue'
import { formatTime } from '@/tool/util'
import { useStore } from 'vuex'
import { Https } from '@/tool/https'
import { Modal, message } from 'ant-design-vue'
import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
import { Modal, message, Input } from 'ant-design-vue'
import { ExclamationCircleOutlined, MoreOutlined } from '@ant-design/icons-vue'
import allUserPoerationsVue from './addAllUser.vue'
import { useI18n } from 'vue-i18n'
export default defineComponent({
components: { allUserPoerationsVue },
components: { allUserPoerationsVue, MoreOutlined },
setup() {
const store: any = useStore()
const currentOrganizationId = computed(
() => store.state.UserHabit.userDetail.organizationId
)
const selectedRowKeys = ref([]) as any
const onSelectChange = (changableRowKeys: string[]) => {
selectedRowKeys.value = changableRowKeys
@@ -202,6 +206,7 @@ export default defineComponent({
}
})
})
const { t } = useI18n()
let filterData: any = reactive({
@@ -217,10 +222,16 @@ export default defineComponent({
systemUser: '',
order: '', //'Ascending 升序 Descending 降序'
orderBy: '',
userName: ''
userName: '',
subscriptionPlanId: ''
})
let renameData: any = ref({}) //修改名字选中的数据
const renamePlanModalVisible = ref(false)
const renamePlanForm = reactive({
planId: null as number | null,
planName: ''
})
const columns: any = computed(() => {
return [
{
@@ -247,13 +258,6 @@ export default defineComponent({
key: 'userName',
width: 150,
ellipsis: true
// customRender: (record: any) => {
// let time = formatTime(
// record.text / 1000,
// "YYYY-MM-DD hh:mm:ss"
// );
// return time;
// },
},
{
title: t('admin.language'),
@@ -277,10 +281,6 @@ export default defineComponent({
{
title: t('admin.Credits'),
align: 'center',
// width: 150,
// minWidth: 100,
// maxWidth: 200,
// resizable: true,
dataIndex: 'credits',
key: 'credits',
width: 100,
@@ -308,7 +308,6 @@ export default defineComponent({
width: 120,
align: 'center',
fixed: 'right',
// slots:{customRender:'action'}
Operations: true
}
]
@@ -353,7 +352,8 @@ export default defineComponent({
(filterData.order = ''), //'Ascending 升序 Descending 降序'
(filterData.orderBy = ''), //'Ascending 升序 Descending 降序'
(filterData.systemUser = ''),
(filterData.userName = '')
(filterData.userName = ''),
(filterData.subscriptionPlanId = '')
}
let setHistoryListData = () => {
let startDate: any = filterData.rangePickerValue?.[0]
@@ -376,18 +376,17 @@ export default defineComponent({
order: filterData.order,
orderBy: filterData.orderBy,
// userName: filterData.userName,
userName: filterData.ids
userName: filterData.ids,
subscriptionPlanId: filterData.subscriptionPlanId
}
return data
}
//获取列表
let gettrialList = () => {
const gettrialList = () => {
filter.tableLoading = true
let data = setHistoryListData()
Https.axiosPost(Https.httpUrls.subAccountList, data).then((rv: any) => {
if (rv) {
console.log(rv)
// this.dataList = rv
filter.dataList = rv.content
filterData.total = rv.total
filter.tableLoading = false
@@ -416,6 +415,66 @@ export default defineComponent({
// 使用 option.label 进行搜索
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
// 订阅计划筛选(按钮点击)
const selectPlanFilter = async (planId: string) => {
filterData.subscriptionPlanId = planId
// 切换管理员订阅计划
Https.axiosGet(Https.httpUrls.switchSubscribePlan, {
params: {
targetSubscriptionPlanId: planId,
adminAccId: store.state.UserHabit.userDetail.id
}
}).then((res: any) => {
console.log(res)
})
searchHistoryList()
}
const planFilterOptions = ref([])
const fetchSubscribePlanList = () => {
const orgId = currentOrganizationId.value
if (!orgId) return
Https.axiosPost(Https.httpUrls.searchSubscribeByOrg, {
organizationId: orgId,
status: ['ACTIVE', 'PENDING']
}).then(res => {
// 将与当前用户 subscriptionPlanId 相同的订阅计划放到第一个
const userSubscriptionPlanId = store.state.UserHabit.userDetail.subscriptionPlanId
if (userSubscriptionPlanId && Array.isArray(res)) {
const sortedList = [...res].sort((a: any, b: any) => {
const isAUserPlan = a.id == userSubscriptionPlanId
const isBUserPlan = b.id == userSubscriptionPlanId
if (isAUserPlan && !isBUserPlan) return -1
if (!isAUserPlan && isBUserPlan) return 1
return 0
})
planFilterOptions.value = sortedList
} else {
planFilterOptions.value = res
}
})
}
// 监听组织ID获取到值后再拉取订阅计划
watch(
() => currentOrganizationId.value,
orgId => {
if (orgId) {
fetchSubscribePlanList()
const userSubscriptionPlanId =
store.state.UserHabit.userDetail.subscriptionPlanId
if (userSubscriptionPlanId) {
selectPlanFilter(userSubscriptionPlanId)
}
}
},
{ immediate: true }
)
// 打开重命名弹窗(基于当前点击的计划)
const openPlanRenameModal = plan => {
renamePlanForm.planId = plan.id
renamePlanForm.planName = plan?.name || ''
renamePlanModalVisible.value = true
console.log(renamePlanForm)
}
let addhHistoryList = () => {
allUserPoerationsVue.value.init({ value: 'Add', label: t('admin.add') }, '')
}
@@ -520,6 +579,33 @@ export default defineComponent({
gettrialList()
})
}
// 确认重命名
const confirmRenamePlan = () => {
if (!renamePlanForm.planName || !renamePlanForm.planName.trim()) {
message.warning(t('admin.PlanNameRequired'))
return
}
Https.axiosPost(Https.httpUrls.updateSubscribePlan, {
id: renamePlanForm.planId,
name: renamePlanForm.planName.trim()
})
.then((rv: any) => {
message.success(t('admin.RenamePlanSuccess'))
renamePlanModalVisible.value = false
fetchSubscribePlanList()
})
.catch((error: any) => {
message.error(error.message || t('admin.RenamePlanFailed'))
})
}
// 取消重命名
const cancelRenamePlan = () => {
renamePlanModalVisible.value = false
renamePlanForm.planId = null
renamePlanForm.planName = ''
}
onMounted(() => {
let allCountry: any = sessionStorage.getItem('allCountry')
if (allCountry) {
@@ -544,7 +630,15 @@ export default defineComponent({
ExportAccountData,
uploadTemplate,
deleteList,
deleteAagree
deleteAagree,
planFilterOptions,
selectPlanFilter,
openPlanRenameModal,
renamePlanModalVisible,
renamePlanForm,
confirmRenamePlan,
cancelRenamePlan,
fetchSubscribePlanList
}
},
data() {
@@ -556,13 +650,35 @@ export default defineComponent({
}
},
mounted() {
let historyTable: any = this.$refs.historyTable
this.historyTableHeight = historyTable.clientHeight - 200
this.updateTableHeight()
window.addEventListener('resize', this.updateTableHeight)
},
methods: {}
beforeUnmount() {
window.removeEventListener('resize', this.updateTableHeight)
},
methods: {
updateTableHeight() {
const historyTable: any = this.$refs.historyTable
if (historyTable) {
// 为底部分页器预留固定空间,使表格部分高度固定且分页器始终可见
this.historyTableHeight = historyTable.clientHeight - 200
}
}
}
})
</script>
<style lang="less" scoped>
.admin_page {
display: flex;
flex-direction: column;
height: 100%;
}
.admin_table_content {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.admin_page .admin_table_search .admin_state {
display: flex;
width: 70%;
@@ -578,10 +694,83 @@ export default defineComponent({
font-size: 1.6rem;
}
}
.plan_list {
margin-top: 1rem;
display: flex;
// flex-wrap: wrap;
padding-left: 2.8rem;
column-gap: 0.6rem;
margin-bottom: 2rem;
.plan_item {
height: 4rem;
width: auto;
min-width: 10rem;
display: flex;
align-items: center;
justify-content: center;
// font-size: 1.8rem;
font-weight: 600;
border-radius: 1.3rem;
color: #fff;
cursor: pointer;
border: 1.8px solid #000;
background-color: #000;
padding: 0 1rem 0 2rem;
&:hover {
color: #000;
background-color: #fff;
}
&.active {
background: #ffffff;
color: #000000;
}
&.disabled {
opacity: 0.5;
cursor: not-allowed;
background-color: #d9d9d9;
border-color: #d9d9d9;
color: #999;
&:hover {
background-color: #d9d9d9;
color: #999;
}
}
}
.plan_item {
column-gap: 0.6rem;
}
.plan_more_icon {
font-size: 1.6rem;
cursor: pointer;
}
}
.subscription-plan-cell {
display: flex;
align-items: center;
justify-content: center;
}
.rename-plan-form {
padding: 2rem 0;
.admin_state_item {
display: flex;
align-items: center;
> span {
width: 10rem;
margin-right: 1rem;
}
}
}
.all-user {
.admin_table_content {
:deep(.ant-table-wrapper) {
overflow: hidden ;
overflow: hidden;
}
}
}

File diff suppressed because it is too large Load Diff