diff --git a/apps/FrontendDesigner/src/views/admin/AdminUsers/AdminUserInvites.vue b/apps/FrontendDesigner/src/views/admin/AdminUsers/AdminUserInvites.vue
index 837cd02..5d8b9e8 100644
--- a/apps/FrontendDesigner/src/views/admin/AdminUsers/AdminUserInvites.vue
+++ b/apps/FrontendDesigner/src/views/admin/AdminUsers/AdminUserInvites.vue
@@ -43,9 +43,9 @@
+
@@ -145,9 +145,9 @@
+
diff --git a/apps/FrontendDesigner/src/views/admin/AdminUsers/AdminUsers.vue b/apps/FrontendDesigner/src/views/admin/AdminUsers/AdminUsers.vue
index 2b1e8a9..ec9e559 100644
--- a/apps/FrontendDesigner/src/views/admin/AdminUsers/AdminUsers.vue
+++ b/apps/FrontendDesigner/src/views/admin/AdminUsers/AdminUsers.vue
@@ -76,9 +76,9 @@
+
diff --git a/apps/FrontendDesigner/src/views/admin/AdminUsers/index.js b/apps/FrontendDesigner/src/views/admin/AdminUsers/index.js
index 452ab08..7f59a5b 100644
--- a/apps/FrontendDesigner/src/views/admin/AdminUsers/index.js
+++ b/apps/FrontendDesigner/src/views/admin/AdminUsers/index.js
@@ -23,7 +23,8 @@ export class AdminOrders {
}
const requestUrl = {
method: adminApi.default.getUserDetail.method,
- url: adminApi.default.getUserDetail.url.replace('USERID', params.id)
+ url: adminApi.default.getUserDetail.url.replace('USERID', params.id),
+ isLoading: adminApi.default.getUserDetail.isLoading
}
return requestUtils.common(requestUrl, params);
}
@@ -35,7 +36,8 @@ export class AdminOrders {
}
const requestUrl = {
method: adminApi.default.updateUserStatus.method,
- url: (adminApi.default.updateUserStatus.url.replace('USERID', params.id))+'?'+'id='+data.id+'&status='+data.status
+ url: (adminApi.default.updateUserStatus.url.replace('USERID', params.id))+'?'+'id='+data.id+'&status='+data.status,
+ isLoading: adminApi.default.updateUserStatus.isLoading
}
return requestUtils.common(requestUrl, params);
}
@@ -47,7 +49,8 @@ export class AdminOrders {
}
const requestUrl = {
method: adminApi.default.updateUserName.method,
- url: adminApi.default.updateUserName.url.replace('USERID', params.id)
+ url: adminApi.default.updateUserName.url.replace('USERID', params.id),
+ isLoading: adminApi.default.updateUserName.isLoading
}
return requestUtils.common(requestUrl, params);
}
@@ -62,7 +65,8 @@ export class AdminOrders {
}
const requestUrl = {
method: adminApi.default.getUsersinvites.method,
- url: adminApi.default.getUsersinvites.url.replace('USERID', params.id)
+ url: adminApi.default.getUsersinvites.url.replace('USERID', params.id),
+ isLoading: adminApi.default.getUsersinvites.isLoading
}
return requestUtils.common(requestUrl, params);
}
@@ -74,7 +78,8 @@ export class AdminOrders {
}
const requestUrl = {
method: adminApi.default.changeRole.method,
- url: adminApi.default.changeRole.url.replace('USERID', params.id)
+ url: adminApi.default.changeRole.url.replace('USERID', params.id),
+ isLoading: adminApi.default.changeRole.isLoading
}
return requestUtils.common(requestUrl, params);
}
@@ -111,4 +116,136 @@ export class AdminOrders {
}
return requestUtils.common(requestUrl, params);
}
+ //创建管理员用户
+ async createAdminUser(data) {
+ let params = {
+ username: data.username || '',
+ email: data.email || '',
+ password: data.password || '',
+ fullName: data.fullName || '',
+ isActive: data.isActive !== undefined ? data.isActive : true,
+ isSuperuser: data.isSuperuser !== undefined ? data.isSuperuser : false,
+ roleIds: Array.isArray(data.roleIds) ? data.roleIds : []
+ }
+ return requestUtils.common(adminApi.default.createAdminUser, params);
+ }
+ //分页查询管理员用户列表
+ async getAdminUsersList(data) {
+ let params = {
+ username: data.username || '',
+ email: data.email || '',
+ isActive: data.isActive !== undefined ? data.isActive : true,
+ pageSize: data.pageSize || 10,
+ pageNum: data.pageNum || 1,
+ orderByColumn: data.orderByColumn || '',
+ isAsc: data.isAsc || 'asc'
+ }
+ return requestUtils.common(adminApi.default.getAdminUserList, params);
+ /**
+ 返回示例:
+ {
+ "code": 0,
+ "success": true,
+ "data": {
+ "total": 9007199254740991,
+ "rows": [
+ {
+ "id": 9007199254740991,
+ "username": "string",
+ "email": "string",
+ "fullName": "string",
+ "isActive": true,
+ "isSuperuser": true,
+ "lastLogin": "2025-12-19T05:33:51.763Z",
+ "createdAt": "2025-12-19T05:33:51.763Z",
+ "updatedAt": "2025-12-19T05:33:51.763Z",
+ "roles": [
+ {
+ "id": 9007199254740991,
+ "roleCode": "string",
+ "roleName": "string",
+ "description": "string"
+ }
+ ]
+ }
+ ],
+ "code": 1073741824,
+ "msg": "string"
+ },
+ "message": "操作成功"
+}
+ */
+ }
+ //更新管理员用户
+ async updateAdminUser(data) {
+ let params = {
+ id: data.id,
+ username: data.username,
+ email: data.email,
+ fullName: data.fullName,
+ isActive: data.isActive,
+ isSuperuser: data.isSuperuser,
+ roleIds: data.roleIds
+ }
+ return requestUtils.common(adminApi.default.updateAdminUser, params);
+ }
+ //启用/禁用用户
+ async enableDisableUser(data) {
+ let params = {
+ userId: data.id,
+ isActive : data.isActive
+ }
+ return requestUtils.common(adminApi.default.toggleAdminUserStatus, params);
+ }
+ //重置用户密码
+ async resetUserPassword(data) {
+ let params = {
+ userId: data.id,
+ newPassword: data.newPassword
+ }
+ return requestUtils.common(adminApi.default.resetAdminUserPassword, params);
+ }
+ //根据用户ID查询管理员用户详情
+ async getAdminUserDetail(data) {
+ let params = {
+ userId : data.id || ''
+ }
+ const requestUrl = {
+ method: adminApi.default.getAdminUserDetail.method,
+ url: adminApi.default.getAdminUserDetail.url.replace('USERID', params.id),
+ isLoading: adminApi.default.getAdminUserDetail.isLoading
+ }
+ return requestUtils.common(requestUrl, params);
+ /**
+ {
+ "code": 0,
+ "success": true,
+ "data": {
+ "id": 9007199254740991,
+ "username": "string",
+ "email": "string",
+ "fullName": "string",
+ "isActive": true,
+ "isSuperuser": true,
+ "lastLogin": "2025-12-19T05:36:04.270Z",
+ "createdAt": "2025-12-19T05:36:04.270Z",
+ "updatedAt": "2025-12-19T05:36:04.270Z",
+ "roles": [
+ {
+ "id": 9007199254740991,
+ "roleCode": "string",
+ "roleName": "string",
+ "description": "string"
+ }
+ ]
+ },
+ "message": "操作成功"
+}
+ */
+ }
+ //批量删除管理员用户
+ async deleteAdminUsers(data) {
+ let arr = data.ids || []
+ return requestUtils.common(adminApi.default.batchDeleteAdminUser, arr);
+ }
}
\ No newline at end of file
diff --git a/apps/frontend/package-lock.json b/apps/frontend/package-lock.json
index 10d7335..09e5180 100644
--- a/apps/frontend/package-lock.json
+++ b/apps/frontend/package-lock.json
@@ -10,7 +10,6 @@
"dependencies": {
"@element-plus/icons-vue": "^2.3.2",
"@google/genai": "^1.27.0",
- "@stripe/stripe-js": "^4.8.0",
"@types/three": "^0.180.0",
"@vuelidate/core": "^2.0.3",
"@vuelidate/validators": "^2.0.4",
@@ -1100,15 +1099,6 @@
"win32"
]
},
- "node_modules/@stripe/stripe-js": {
- "version": "4.10.0",
- "resolved": "https://registry.npmmirror.com/@stripe/stripe-js/-/stripe-js-4.10.0.tgz",
- "integrity": "sha512-KrMOL+sH69htCIXCaZ4JluJ35bchuCCznyPyrbN8JXSGQfwBI1SuIEMZNwvy8L8ykj29t6sa5BAAiL7fNoLZ8A==",
- "license": "MIT",
- "engines": {
- "node": ">=12.16"
- }
- },
"node_modules/@tweenjs/tween.js": {
"version": "23.1.3",
"resolved": "https://registry.npmmirror.com/@tweenjs/tween.js/-/tween.js-23.1.3.tgz",
diff --git a/apps/frontend/package.json b/apps/frontend/package.json
index 8d8b57a..5d18916 100644
--- a/apps/frontend/package.json
+++ b/apps/frontend/package.json
@@ -13,7 +13,6 @@
"dependencies": {
"@element-plus/icons-vue": "^2.3.2",
"@google/genai": "^1.27.0",
- "@stripe/stripe-js": "^4.8.0",
"@twind/core": "^1.1.3",
"@twind/preset-autoprefix": "^1.0.7",
"@twind/preset-tailwind": "^1.1.4",
@@ -24,6 +23,7 @@
"country-state-city": "^3.2.1",
"dayjs": "^1.11.13",
"element-plus": "^2.11.7",
+ "install": "^0.13.0",
"jose": "^6.1.1",
"motion-v": "^1.7.4",
"normalize.css": "^8.0.1",
diff --git a/apps/frontend/src/components/IPCard/index.vue b/apps/frontend/src/components/IPCard/index.vue
index 035e839..e49d034 100644
--- a/apps/frontend/src/components/IPCard/index.vue
+++ b/apps/frontend/src/components/IPCard/index.vue
@@ -98,7 +98,9 @@ const isTouching = ref(false);
const isControlsVisible = ref(false);
const cjimg = 'https://draft-user.s3.us-east-2.amazonaws.com/images/14f98f33-06a7-4629-a42e-d7cfbced786f';
const anTypeImg = 'https://draft-user.s3.us-east-2.amazonaws.com/images/1e82b2b6-0e5d-4a62-b65f-098952eb2f67';
-const humanTypeImg = 'https://draft-user.s3.us-east-2.amazonaws.com/images/e3e60cc7-9777-41ba-9d1e-f5ffc92e4fac.webp';
+// const humanTypeImg = 'https://draft-user.s3.us-east-2.amazonaws.com/images/e3e60cc7-9777-41ba-9d1e-f5ffc92e4fac.webp';
+// const humanTypeImg = 'https://draft-user.s3.us-east-2.amazonaws.com/images/61770f50-4b87-40a0-9297-cabda0ec6317.webp'
+const humanTypeImg = ''
const giminiServer = new GiminiServer();
// 图片比例
const imageAspectRatio = ref(9/16); // 默认比例
@@ -218,9 +220,9 @@ const handleGenerateImage = async () => {
}
if(props?.cardData?.ipType){
if(props?.cardData?.ipType==1){
- referenceImages.push(humanTypeImg);
+ humanTypeImg&&referenceImages.push(humanTypeImg);
}else{
- referenceImages.push(anTypeImg);
+ anTypeImg&&referenceImages.push(anTypeImg);
}
}
if(iscjt){
@@ -277,6 +279,8 @@ const handleGenerateImage = async () => {
保证角色所有的服饰衣服都为木头材质颜色,并且要带一些木头纹理,颜色为#e2cfb3。
`
;
+ // 角色姿势:${props.cardData.ipType==1?``:``}
+
if(props.cardData.prompt&&props.cardData.prompt.indexOf('nospec')!=-1){
prompt = '按原图生成'
referenceImages = [props.cardData.inspirationImage];
diff --git a/apps/frontend/src/components/IPCard/tsc.js b/apps/frontend/src/components/IPCard/tsc.js
index bf63c5b..9724db6 100644
--- a/apps/frontend/src/components/IPCard/tsc.js
+++ b/apps/frontend/src/components/IPCard/tsc.js
@@ -140,4 +140,18 @@
// 保证角色所有的服饰衣服都为木头材质颜色,并且要带一些木头纹理,颜色为#bfa888。
// `
+const qwentsc = `
+角色肤色和衣服材质都为纯色一种颜色如下:
+ 重点:保证角色所有的服饰衣服都为木头材质颜色,并且要带一些木头纹理,颜色为#e2cfb3
+ 一个通体由单一纯色木材雕刻而成的角色,整体呈现木质雕塑或木偶风格.
+ A full-body character portrait
+ 角色特征:Q 版萌系造型,头身比例夸张(大头小身),神态纯真,服饰设计融合童话风与复古感
+ 姿势:身体笔直,正对镜头,双臂自然下垂但略微外展,肘部微屈约15度,手掌张开、放松,掌心朝向身体内侧。
+ 双腿并拢伸直,双脚平放于地面,脚尖朝前。
+ 眼睛放大设计:眼眶结构宽大清晰,单侧眼球/眼窝直径不小于2cm(即半径≥1cm),预留足够空间用于嵌入镜头设备,眼型饱满、边缘厚实,适合3D打印安装。
+ 嘴巴小巧,表情温柔童真。
+ Style:潮玩盲盒角色设计,采用 3D 立体建模渲染,呈现细腻的质感与精致的细节。
+ Note: The image should not have white borders.
+ 去除原图中复杂的背景,只保留人物角色的主体。
+`
export const cjt = `将玩偶放在桌子玻璃正中间上,原图放在图中桌面上的相框里面[CJT_DEOTA]`
diff --git a/apps/frontend/src/components/StripePaymentForm.vue b/apps/frontend/src/components/StripePaymentForm.vue
index bbd8a87..4162542 100644
--- a/apps/frontend/src/components/StripePaymentForm.vue
+++ b/apps/frontend/src/components/StripePaymentForm.vue
@@ -61,11 +61,8 @@
import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
import { ElMessage, ElLoading } from 'element-plus'
import { CreditCard, Lock } from '@element-plus/icons-vue'
-import { loadStripe } from '@stripe/stripe-js'
import { useI18n } from 'vue-i18n'
import { PayServer } from '@deotaland/utils'
-// 模拟Stripe公钥(生产环境中应该从环境变量获取)
-const STRIPE_PUBLISHABLE_KEY = import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY
const { t } = useI18n()
// Props
const props = defineProps({
@@ -90,8 +87,6 @@ const props = defineProps({
// Emits
const emit = defineEmits(['payment-success', 'payment-error', 'cancel'])
-// 响应式数据
-const stripe = ref(null)
const elements = ref(null)
const cardElement = ref(null)
const processing = ref(false)
@@ -102,6 +97,7 @@ const couponSuccess = ref('')
const discountAmount = ref(0)
const taxAmount = ref(0)
const shippingAmount = ref(0)
+const isInitialized = ref(false) // 防止重复初始化
// 支付方式选项
// 仅支持 Stripe 卡片支付
@@ -115,6 +111,11 @@ const finalAmount = computed(() => {
const payServer = new PayServer()
// 初始化Stripe
const initializeStripe = async () => {
+ // 防止重复初始化
+ if (isInitialized.value) {
+ return;
+ }
+
try {
const data = await payServer.createPaymentIntent(finalAmount.value, props.currency, {
order_id: props.orderId,
@@ -122,6 +123,8 @@ const initializeStripe = async () => {
})
elements.value = data.element
cardElement.value = data.cardElement
+ isInitialized.value = true;
+
// 监听卡片验证错误
cardElement.value.on('change', ({ error }) => {
const displayError = document.getElementById('card-errors')
@@ -249,6 +252,8 @@ onUnmounted(() => {
if (elements.value) {
elements.value = null
}
+ // 重置初始化标志
+ isInitialized.value = false;
})
// 监听金额变化,重新计算费用
diff --git a/apps/frontend/src/components/auth/PhoneLoginForm.vue b/apps/frontend/src/components/auth/PhoneLoginForm.vue
new file mode 100644
index 0000000..81d96ff
--- /dev/null
+++ b/apps/frontend/src/components/auth/PhoneLoginForm.vue
@@ -0,0 +1,711 @@
+
+
+
+
+
+
+
diff --git a/apps/frontend/src/components/iPandCardLeft/index.vue b/apps/frontend/src/components/iPandCardLeft/index.vue
index 09fc183..f26c5ad 100644
--- a/apps/frontend/src/components/iPandCardLeft/index.vue
+++ b/apps/frontend/src/components/iPandCardLeft/index.vue
@@ -24,6 +24,34 @@
+
+
+
+
@@ -310,6 +338,48 @@ const handleIpTypeSelect = (type) => {
// // 忽略本地存储异常
// }
};
+
+// 模型选择相关
+const selectedModelId = ref(null);
+const availableModels = ref([
+ {
+ id: 'nano_banana',
+ name: 'Nano Banana',
+ description: '快速生成',
+ model: 'gemini-2.5-flash-image'
+ },
+ {
+ id: 'nano_banana_pro',
+ name: 'Nano Banana Pro',
+ description: '高质量生成',
+ model: 'gemini-3-pro-image-preview'
+ },
+ {
+ id: 'doubao',
+ name: 'Doubao',
+ description: '豆包模型',
+ model: 'doubao'
+ },
+ {
+ id: 'qwimg',
+ name: 'QwImg',
+ description: '通义千问',
+ model: 'ali'
+ }
+]);
+
+// 处理模型选择
+const handleModelSelect = (modelId) => {
+ selectedModelId.value = modelId;
+ const selectedModel = availableModels.value.find(m => m.id === modelId);
+ // 保存到本地存储
+ try {
+ localStorage.setItem('selectedModelId', modelId);
+ localStorage.setItem('selectedModel', JSON.stringify(selectedModel));
+ } catch (e) {
+ // 忽略本地存储异常
+ }
+};
// 新增:电子模块和草图选择相关状态
const selectedModule = ref(null); // 选中的电子模块
const selectedSketch = ref(null); // 选中的草图
@@ -323,6 +393,19 @@ const selectedSkinColor = ref(null); // 选中的肤色
const expressions = ref([]);
const init = () => {
+ // 从本地存储加载模型选择
+ try {
+ const savedModelId = localStorage.getItem('selectedModelId');
+ if (savedModelId) {
+ selectedModelId.value = savedModelId;
+ } else {
+ // 默认选择第一个模型
+ selectedModelId.value = availableModels.value[0].id;
+ }
+ } catch (e) {
+ // 如果加载失败,使用默认模型
+ selectedModelId.value = availableModels.value[0].id;
+ }
}
onMounted(() => {
init()
@@ -1008,6 +1091,27 @@ onMounted(() => {
font-weight: 500;
}
+/* 模型选择样式 */
+.model-select {
+ width: 100%;
+}
+
+.model-option {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+}
+
+.model-option .model-name {
+ font-weight: 600;
+ color: var(--el-text-color-primary);
+}
+
+.model-option .model-description {
+ font-size: 12px;
+ color: var(--el-text-color-secondary);
+}
+
/* 适应亮色主题 */
:root {
--border-color: rgba(0, 0, 0, 0.1);
@@ -1042,6 +1146,11 @@ onMounted(() => {
border-color: #A78BFA;
}
+/* 模型选择在亮色主题下的样式 */
+.model-select {
+ width: 100%;
+}
+
.logo-container {
display: flex;
align-items: center;
@@ -1099,7 +1208,7 @@ onMounted(() => {
/* 选择框样式 */
.model-select {
width: 100%;
- padding: 10px 12px;
+ /* padding: 10px 12px; */
background-color: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 6px;
diff --git a/apps/frontend/src/components/layout/AppSidebar.vue b/apps/frontend/src/components/layout/AppSidebar.vue
index 93da40d..3e8231e 100644
--- a/apps/frontend/src/components/layout/AppSidebar.vue
+++ b/apps/frontend/src/components/layout/AppSidebar.vue
@@ -44,7 +44,7 @@
🪄
{{ remainingPoints }}
-->
-
+