41 Commits

Author SHA1 Message Date
wxd
967996429b 更新 .gitea/workflows/prod_build_schedule.yaml 2026-03-23 10:45:31 +08:00
wxd
f88129f8a9 更新 .gitea/workflows/prod_build_schedule.yaml 2026-03-13 14:02:26 +08:00
wxd
02ccd546bc 更新 .gitea/workflows/prod_build_schedule.yaml 2026-03-06 18:45:13 +08:00
wxd
4006e7f1c1 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 3m6s
2026-03-05 10:59:08 +08:00
wxd
352f2b7bae 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 3m22s
2026-03-02 09:52:19 +08:00
wxd
1839bae545 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 3m25s
2026-02-24 11:38:54 +08:00
wxd
93cb27238b 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 1m54s
2026-02-06 14:18:58 +08:00
wxd
a0de3ce96d 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 1m51s
2026-02-06 10:37:16 +08:00
wxd
989c8468f0 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 2m9s
2026-02-05 16:44:03 +08:00
wxd
f8a864d740 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 1m55s
2026-02-04 15:59:53 +08:00
wxd
afde6d2024 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 2m49s
2026-02-03 09:40:44 +08:00
fe4b39ac97 更新 .gitea/workflows/research_build_manual.yaml 2026-02-02 10:34:19 +08:00
c25e5042dd 上传文件至「.gitea/workflows」 2026-02-02 10:33:11 +08:00
wxd
27849503b3 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 1m56s
2026-01-29 16:56:04 +08:00
wxd
5fdf071510 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 1m48s
2026-01-29 16:32:36 +08:00
wxd
ff3e62506c 更新 .gitea/workflows/prod_build_schedule.yaml 2026-01-29 16:32:27 +08:00
wxd
24accf803d 更新 .gitea/workflows/prod_build_schedule.yaml 2026-01-29 09:55:57 +08:00
wxd
b5dcc80759 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 1m55s
2026-01-28 16:36:56 +08:00
wxd
a294116696 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 3m8s
2026-01-28 10:06:12 +08:00
wxd
d45f0b0ecd 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 2m1s
2026-01-27 14:18:56 +08:00
wxd
2a522e06a0 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 3m46s
2026-01-27 10:16:57 +08:00
wxd
af3bff6d80 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 5m20s
2026-01-26 16:45:17 +08:00
wxd
d9d57066fc 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 3m59s
2026-01-24 11:56:59 +08:00
wxd
e34986d09d 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 2m5s
2026-01-23 22:32:58 +08:00
wxd
57adf91646 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 2m5s
2026-01-23 21:44:02 +08:00
wxd
016c1de922 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 3m53s
2026-01-23 15:46:05 +08:00
wxd
a167d3f2ba 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 3m55s
2026-01-21 16:59:55 +08:00
wxd
fb7bf53680 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 3m47s
2026-01-20 16:49:28 +08:00
wxd
cb453297be 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 3m55s
2026-01-15 10:52:10 +08:00
wxd
a2f4f946ac 更新 .gitea/workflows/prod_build_schedule.yaml 2026-01-14 17:10:29 +08:00
67d5bb6874 2025.12.19 生产部署
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 3m35s
2025-12-19 17:47:22 +08:00
db20117500 2025.12.17 生产部署
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 3m32s
2025-12-17 14:03:27 +08:00
f3e4408dc0 更新 .gitea/workflows/prod_build_schedule.yaml
All checks were successful
AiDA WEB-Node.js 生产分支构建部署 / build (18.18.0) (push) Successful in 2m14s
2025-12-16 21:50:38 +08:00
c2d13187f0 2025.12.16 生产部署 2025-12-16 17:24:46 +08:00
7155dedc8d 更新 .gitea/workflows/prod_build_schedule.yaml 2025-12-16 17:23:32 +08:00
de8a6b9dc7 上传文件至「.gitea/workflows」 2025-12-01 17:13:08 +08:00
9c562143da 更新 .gitea/workflows/prod_build_manual.yaml 2025-11-29 00:07:07 +08:00
21fb901580 更新 .gitea/workflows/prod_build_schedule.yaml 2025-11-29 00:06:19 +08:00
29eb464772 更新 .gitea/workflows/prod_build_schedule.yaml
Some checks failed
AiDA WEB-Node.js StableVersion 分支构建部署 / build (18.18.0) (push) Failing after 2m34s
2025-11-28 17:36:57 +08:00
6f5d696c2d 更新 .gitea/workflows/prod_build_schedule.yaml 2025-11-28 17:35:50 +08:00
14a3e467f8 更新 .gitea/workflows/develop_build_commit.yaml 2025-11-28 16:07:40 +08:00
50 changed files with 1545 additions and 2137 deletions

View File

@@ -0,0 +1,90 @@
name: git commit 控制 AiDA WEB-Node.js 开发分支构建部署
on:
workflow_dispatch:
push:
branches:
- dev_vite
jobs:
build:
runs-on: ubuntu-latest
if: "contains(github.event.head_commit.message, '[run build]')"
strategy:
matrix:
node-version: [ 18.18.0 ]
env:
REMOTE_DEPLOY_PATH: /workspace/workspace_aida/DevelopVersion/develop-aida-web-front
steps:
- name: 0.记录开始时间
id: build_start_time
run: echo "current_time=$(TZ='Asia/Hong_Kong' date '+%Y-%m-%d %H:%M:%S %Z')" >> $GITHUB_OUTPUT
- name: 1.检出代码
uses: actions/checkout@v4
with:
ref: dev_vite
- name: 2.设置 Node.js 环境
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm run build:dev
- run: ls -l
- name: 3.同步文件到远程服务器
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_KEY }}
source: "./dist/*"
target: ${{ env.REMOTE_DEPLOY_PATH }}
ssh_options: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
strip_components: 0
- name: 4. 远程重载 Nginx 配置
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_KEY }}
# 核心:执行 Nginx 重载命令
script: |
echo "尝试重载 Nginx 服务..."
# 💡 注意:执行此命令需要服务器用户具有 sudo 权限,并且配置了 NOPASSWD。
# 否则工作流可能会因为权限不足而失败。
sudo systemctl reload nginx
echo "Nginx 重载命令已发送。"
- name: 5.发送构建结果邮件
if: always() # 无论上一步是否失败,都执行此步骤
uses: dawidd6/action-send-mail@v3
with:
from: ${{ secrets.MAIL_USERNAME }}
# --- 邮件配置 ---
server_address: smtp.gmail.com # 替换为你的SMTP服务器地址
server_port: 465 # 替换为你的SMTP端口 (通常是465或587)
username: ${{ secrets.MAIL_USERNAME }} # 存储在Secrets中的邮箱用户名
password: ${{ secrets.MAIL_PASSWORD }} # 存储在Secrets中的邮箱密码
subject: 'Gitea Actions 构建通知: ${{ job.status }} - AiDA back-java Develop'
# 收件人列表,可以根据需要更改
to: 'xupei3360@163.com,txli@aidlab.hk,cgzhou@aidlab.hk,zchengrong@yeah.net' # 替换为实际收件人邮箱
# --- 邮件正文内容 ---
body: |
项目: AiDA back-java Develop
分支: dev/3.1_release_merge
🎉 构建结果: ${{ job.status }}
📅 构建时间: ${{ steps.build_start_time.outputs.current_time }}
🔗 构建链接: ${{ gitea.server_url }}/${{ gitea.repository.owner.name }}/${{ gitea.repository.name }}/actions/runs/${{ gitea.run_id }}
# 确保邮件内容为纯文本,或者你可以设置为 html: true 并调整 body
content_type: text/plain

View File

@@ -0,0 +1,85 @@
name: 手动触发 AiDA WEB-Node.js 开发分支构建部署
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [ 18.18.0 ]
env:
REMOTE_DEPLOY_PATH: /workspace/workspace_aida/DevelopVersion/develop-aida-web-front
steps:
- name: 0.记录开始时间
id: build_start_time
run: echo "current_time=$(TZ='Asia/Hong_Kong' date '+%Y-%m-%d %H:%M:%S %Z')" >> $GITHUB_OUTPUT
- name: 1.检出代码
uses: actions/checkout@v4
with:
ref: dev_vite
- name: 2.设置 Node.js 环境
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm run build:dev
- run: ls -l
- name: 3.同步文件到远程服务器
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_KEY }}
source: "./dist/*"
target: ${{ env.REMOTE_DEPLOY_PATH }}
ssh_options: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
strip_components: 0
- name: 4. 远程重载 Nginx 配置
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_KEY }}
# 核心:执行 Nginx 重载命令
script: |
echo "尝试重载 Nginx 服务..."
# 💡 注意:执行此命令需要服务器用户具有 sudo 权限,并且配置了 NOPASSWD。
# 否则工作流可能会因为权限不足而失败。
sudo systemctl reload nginx
echo "Nginx 重载命令已发送。"
- name: 5.发送构建结果邮件
if: always() # 无论上一步是否失败,都执行此步骤
uses: dawidd6/action-send-mail@v3
with:
from: ${{ secrets.MAIL_USERNAME }}
# --- 邮件配置 ---
server_address: smtp.gmail.com # 替换为你的SMTP服务器地址
server_port: 465 # 替换为你的SMTP端口 (通常是465或587)
username: ${{ secrets.MAIL_USERNAME }} # 存储在Secrets中的邮箱用户名
password: ${{ secrets.MAIL_PASSWORD }} # 存储在Secrets中的邮箱密码
subject: 'Gitea Actions 构建通知: ${{ job.status }} - AiDA back-java Develop'
# 收件人列表,可以根据需要更改
to: 'xupei3360@163.com,txli@aidlab.hk,cgzhou@aidlab.hk,zchengrong@yeah.net' # 替换为实际收件人邮箱
# --- 邮件正文内容 ---
body: |
项目: AiDA back-java Develop
分支: dev/3.1_release_merge
🎉 构建结果: ${{ job.status }}
📅 构建时间: ${{ steps.build_start_time.outputs.current_time }}
🔗 构建链接: ${{ gitea.server_url }}/${{ gitea.repository.owner.name }}/${{ gitea.repository.name }}/actions/runs/${{ gitea.run_id }}
# 确保邮件内容为纯文本,或者你可以设置为 html: true 并调整 body
content_type: text/plain

View File

@@ -0,0 +1,78 @@
name: AiDA WEB-Node.js 生产分支构建部署
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [ 18.18.0 ]
steps:
- name: 0.记录开始时间
id: build_start_time
run: echo "current_time=$(TZ='Asia/Hong_Kong' date '+%Y-%m-%d %H:%M:%S %Z')" >> $GITHUB_OUTPUT
- name: 1.检出代码
uses: actions/checkout@v4
with:
ref: StableVersion
- name: 2.设置 Node.js 环境
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm run build
- run: ls -l
- name: 3.5. 手动安装 AWS CLI v2 # 新增步骤:确保 aws 命令可用
run: |
echo "安装 AWS CLI V2..."
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install --update
aws --version
echo "AWS CLI V2 安装完成。"
- name: 4.配置 AWS 凭证
uses: aws-actions/configure-aws-credentials@main
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: 'ap-east-1'
- name: 5.同步 dist 目录到 S3
run: |
aws s3 sync dist/ s3://${{ secrets.S3_BUCKET_NAME }}/ --acl public-read
- name: 6.发送构建结果邮件
if: always() # 无论上一步是否失败,都执行此步骤
uses: dawidd6/action-send-mail@v3
with:
from: ${{ secrets.MAIL_USERNAME }}
# --- 邮件配置 ---
server_address: smtp.gmail.com # 替换为你的SMTP服务器地址
server_port: 465 # 替换为你的SMTP端口 (通常是465或587)
username: ${{ secrets.MAIL_USERNAME }} # 存储在Secrets中的邮箱用户名
password: ${{ secrets.MAIL_PASSWORD }} # 存储在Secrets中的邮箱密码
subject: 'Gitea Actions 构建通知: ${{ job.status }} - AiDA back-java Develop'
# 收件人列表,可以根据需要更改
to: 'xupei3360@163.com,txli@aidlab.hk,cgzhou@aidlab.hk,zchengrong@yeah.net' # 替换为实际收件人邮箱
# --- 邮件正文内容 ---
body: |
项目: AiDA back-java Develop
分支: dev/3.1_release_merge
🎉 构建结果: ${{ job.status }}
📅 构建时间: ${{ steps.build_start_time.outputs.current_time }}
🔗 构建链接: ${{ gitea.server_url }}/${{ gitea.repository.owner.name }}/${{ gitea.repository.name }}/actions/runs/${{ gitea.run_id }}
# 确保邮件内容为纯文本,或者你可以设置为 html: true 并调整 body
content_type: text/plain

View File

@@ -0,0 +1,81 @@
name: AiDA WEB-Node.js 生产分支构建部署
on:
schedule:
# cron为UTC时区构建时间=部署时间-8小时 {*分 (-8)时 *日 *月 *周} ---
# 示例: 1月1日22点22分触发构建 cron写作 - '22 14 1 1 *'
- cron: '00 14 23 3 *'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [ 18.18.0 ]
steps:
- name: 0.记录开始时间
id: build_start_time
run: echo "current_time=$(TZ='Asia/Hong_Kong' date '+%Y-%m-%d %H:%M:%S %Z')" >> $GITHUB_OUTPUT
- name: 1.检出代码
uses: actions/checkout@v4
with:
ref: StableVersion
- name: 2.设置 Node.js 环境
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm run build
- run: ls -l
- name: 3.5. 手动安装 AWS CLI v2 # 新增步骤:确保 aws 命令可用
run: |
echo "安装 AWS CLI V2..."
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install --update
aws --version
echo "AWS CLI V2 安装完成。"
- name: 4.配置 AWS 凭证
uses: aws-actions/configure-aws-credentials@main
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: 'ap-east-1'
- name: 5.同步 dist 目录到 S3
run: |
aws s3 sync dist/ s3://${{ secrets.S3_BUCKET_NAME }}/ --acl public-read
- name: 6.发送构建结果邮件
if: always() # 无论上一步是否失败,都执行此步骤
uses: dawidd6/action-send-mail@v3
with:
from: ${{ secrets.MAIL_USERNAME }}
# --- 邮件配置 ---
server_address: smtp.gmail.com # 替换为你的SMTP服务器地址
server_port: 465 # 替换为你的SMTP端口 (通常是465或587)
username: ${{ secrets.MAIL_USERNAME }} # 存储在Secrets中的邮箱用户名
password: ${{ secrets.MAIL_PASSWORD }} # 存储在Secrets中的邮箱密码
subject: 'Gitea Actions 构建通知: ${{ job.status }} - AiDA back-java Develop'
# 收件人列表,可以根据需要更改
to: 'cgzhou@aidlab.hk,zchengrong@yeah.net' # 替换为实际收件人邮箱
# --- 邮件正文内容 ---
body: |
项目: AiDA WEB-Node.js 生产分支构建部署
分支: StableVersion
🎉 构建结果: ${{ job.status }}
📅 构建时间: ${{ steps.build_start_time.outputs.current_time }}
🔗 构建链接: ${{ gitea.server_url }}/${{ gitea.repository.owner.name }}/${{ gitea.repository.name }}/actions/runs/${{ gitea.run_id }}
# 确保邮件内容为纯文本,或者你可以设置为 html: true 并调整 body
content_type: text/plain

View File

@@ -0,0 +1,85 @@
name: 手动触发 AiDA WEB-Node.js 开发分支构建部署
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [ 18.18.0 ]
env:
REMOTE_DEPLOY_PATH: /workspace/workspace_aida/Research/research-aida-web-front
steps:
- name: 0.记录开始时间
id: build_start_time
run: echo "current_time=$(TZ='Asia/Hong_Kong' date '+%Y-%m-%d %H:%M:%S %Z')" >> $GITHUB_OUTPUT
- name: 1.检出代码
uses: actions/checkout@v4
with:
ref: research
- name: 2.设置 Node.js 环境
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm run build:dev
- run: ls -l
- name: 3.同步文件到远程服务器
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_KEY }}
source: "./dist/*"
target: ${{ env.REMOTE_DEPLOY_PATH }}
ssh_options: "-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
strip_components: 0
- name: 4. 远程重载 Nginx 配置
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_KEY }}
# 核心:执行 Nginx 重载命令
script: |
echo "尝试重载 Nginx 服务..."
# 💡 注意:执行此命令需要服务器用户具有 sudo 权限,并且配置了 NOPASSWD。
# 否则工作流可能会因为权限不足而失败。
sudo systemctl reload nginx
echo "Nginx 重载命令已发送。"
- name: 5.发送构建结果邮件
if: always() # 无论上一步是否失败,都执行此步骤
uses: dawidd6/action-send-mail@v3
with:
from: ${{ secrets.MAIL_USERNAME }}
# --- 邮件配置 ---
server_address: smtp.gmail.com # 替换为你的SMTP服务器地址
server_port: 465 # 替换为你的SMTP端口 (通常是465或587)
username: ${{ secrets.MAIL_USERNAME }} # 存储在Secrets中的邮箱用户名
password: ${{ secrets.MAIL_PASSWORD }} # 存储在Secrets中的邮箱密码
subject: 'Gitea Actions 构建通知: ${{ job.status }} - AiDA back-java Develop'
# 收件人列表,可以根据需要更改
to: 'xupei3360@163.com,txli@aidlab.hk,cgzhou@aidlab.hk,zchengrong@yeah.net' # 替换为实际收件人邮箱
# --- 邮件正文内容 ---
body: |
项目: AiDA back-java Develop
分支: dev/3.1_release_merge
🎉 构建结果: ${{ job.status }}
📅 构建时间: ${{ steps.build_start_time.outputs.current_time }}
🔗 构建链接: ${{ gitea.server_url }}/${{ gitea.repository.owner.name }}/${{ gitea.repository.name }}/actions/runs/${{ gitea.run_id }}
# 确保邮件内容为纯文本,或者你可以设置为 html: true 并调整 body
content_type: text/plain

BIN
dist.7z Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 KiB

View File

@@ -1,16 +1,7 @@
<template>
<router-view/>
<div class="loading" v-show="loading"><a-spin :delay="0.5" /></div>
</template>
<script setup>
import { computed } from 'vue';
import { useStore } from 'vuex';
const store = useStore();
const loading = computed(() => store.state.loading || store.state.view_loading);
</script>
<style lang="less">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
@@ -18,19 +9,7 @@
-moz-osx-font-smoothing: grayscale;
height: 100%;
}
.loading{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.4);
display: flex;
align-items: center;
justify-content: center;
z-index: 999999999999;
color: #fff;
}
.ipad{
*{
-webkit-touch-callout:none;

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.5 KiB

View File

@@ -1,10 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2427_2565)">
<path d="M12 0C5.37264 0 0 5.37264 0 12C0 17.6275 3.87456 22.3498 9.10128 23.6467V15.6672H6.62688V12H9.10128V10.4198C9.10128 6.33552 10.9498 4.4424 14.9597 4.4424C15.72 4.4424 17.0318 4.59168 17.5685 4.74048V8.06448C17.2853 8.03472 16.7933 8.01984 16.1822 8.01984C14.2147 8.01984 13.4544 8.76528 13.4544 10.703V12H17.3741L16.7006 15.6672H13.4544V23.9122C19.3963 23.1946 24.0005 18.1354 24.0005 12C24 5.37264 18.6274 0 12 0Z" fill="#2C2C2C"/>
</g>
<defs>
<clipPath id="clip0_2427_2565">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

View File

@@ -1,10 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2427_2564)">
<path d="M22.2234 0H1.77187C0.792187 0 0 0.773438 0 1.72969V22.2656C0 23.2219 0.792187 24 1.77187 24H22.2234C23.2031 24 24 23.2219 24 22.2703V1.72969C24 0.773438 23.2031 0 22.2234 0ZM7.12031 20.4516H3.55781V8.99531H7.12031V20.4516ZM5.33906 7.43438C4.19531 7.43438 3.27188 6.51094 3.27188 5.37187C3.27188 4.23281 4.19531 3.30937 5.33906 3.30937C6.47813 3.30937 7.40156 4.23281 7.40156 5.37187C7.40156 6.50625 6.47813 7.43438 5.33906 7.43438ZM20.4516 20.4516H16.8937V14.8828C16.8937 13.5563 16.8703 11.8453 15.0422 11.8453C13.1906 11.8453 12.9094 13.2938 12.9094 14.7891V20.4516H9.35625V8.99531H12.7687V10.5609H12.8156C13.2891 9.66094 14.4516 8.70938 16.1813 8.70938C19.7859 8.70938 20.4516 11.0813 20.4516 14.1656V20.4516V20.4516Z" fill="#2C2C2C"/>
</g>
<defs>
<clipPath id="clip0_2427_2564">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 997 B

View File

@@ -1,10 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2426_2350)">
<path d="M23.5233 7.12823C23.5233 7.12823 23.2913 5.49009 22.5766 4.77079C21.6717 3.8241 20.6601 3.81946 20.196 3.76377C16.8733 3.52246 11.8846 3.52246 11.8846 3.52246H11.8754C11.8754 3.52246 6.88669 3.52246 3.564 3.76377C3.09994 3.81946 2.08828 3.8241 1.18336 4.77079C0.468703 5.49009 0.241312 7.12823 0.241312 7.12823C0.241312 7.12823 0 9.05409 0 10.9753V12.7759C0 14.6971 0.236672 16.6229 0.236672 16.6229C0.236672 16.6229 0.468703 18.2611 1.17872 18.9804C2.08364 19.9271 3.27164 19.8946 3.80067 19.9967C5.70333 20.1777 11.88 20.2334 11.88 20.2334C11.88 20.2334 16.8733 20.2241 20.196 19.9874C20.6601 19.9317 21.6717 19.9271 22.5766 18.9804C23.2913 18.2611 23.5233 16.6229 23.5233 16.6229C23.5233 16.6229 23.76 14.7017 23.76 12.7759V10.9753C23.76 9.05409 23.5233 7.12823 23.5233 7.12823ZM9.42511 14.9616V8.28374L15.8431 11.6343L9.42511 14.9616Z" fill="#2C2C2C"/>
</g>
<defs>
<clipPath id="clip0_2426_2350">
<rect width="23.76" height="23.76" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@@ -1,3 +0,0 @@
<svg width="21" height="24" viewBox="0 0 21 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.9218 0H10.9175V16.1843C10.9175 18.1127 9.37747 19.6967 7.4609 19.6967C5.54433 19.6967 4.00424 18.1127 4.00424 16.1843C4.00424 14.2905 5.51011 12.7408 7.35825 12.672V8.60871C3.28553 8.67755 0 12.0177 0 16.1843C0 20.3854 3.35398 23.76 7.49514 23.76C11.6362 23.76 14.9902 20.351 14.9902 16.1843V7.88555C16.4961 8.98748 18.3442 9.64174 20.295 9.67619V5.61287C17.2833 5.50957 14.9218 3.03026 14.9218 0Z" fill="#2C2C2C"/>
</svg>

Before

Width:  |  Height:  |  Size: 532 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 KiB

View File

@@ -1250,14 +1250,10 @@ tr > .ant-picker-cell-in-view.ant-picker-cell-range-hover-start:last-child::afte
background: #000 !important;
border-color: #000 !important;
}
.ant-spin .ant-spin-dot {
width: 1.5em;
height: 1.5em;
}
.ant-spin-dot-item {
background-color: #000000 !important;
width: 0.9em !important;
height: 0.9em !important;
width: 9px !important;
height: 9px !important;
}
.ant-spin {
color: #000;

View File

@@ -1378,14 +1378,10 @@ tr > .ant-picker-cell-in-view.ant-picker-cell-range-hover-start:last-child::afte
}
}
//loding样式
.ant-spin .ant-spin-dot{
width: 1.5em;
height: 1.5em;
}
.ant-spin-dot-item{
background-color: #000000 !important;
width: .9em !important;
height: .9em !important;
width: 9px !important;
height: 9px !important;
}
.ant-spin{
color: #000;

View File

@@ -1,848 +0,0 @@
<template>
<div class="subscription-plan">
<a-card class="search-card" :bordered="false">
<a-form
class="search-form"
layout="inline"
:model="searchForm"
:label-col="{ style: { width: '12rem' } }"
:wrapper-col="{ style: { width: '22rem' } }"
>
<a-form-item label="ID">
<a-input v-model:value="searchForm.id" allow-clear placeholder="Input the id" />
</a-form-item>
<a-form-item label="Name">
<a-input
v-model:value="searchForm.name"
allow-clear
placeholder="Input the name"
/>
</a-form-item>
<a-form-item label="Time Range">
<a-range-picker
v-model:value="searchForm.dateRange"
value-format="X"
allow-clear
/>
</a-form-item>
<a-form-item label="Organization">
<a-select
v-model:value="searchForm.organizationId"
allow-clear
placeholder="Select Organization"
style="width: 180px"
@popupScroll="handleOrganizationScroll"
@select="handleOrganizationSelect"
@change="handleOrganizationChange"
>
<a-select-option value="ADD_ORGANIZATION" class="add-organization-option">
+ 添加组织
</a-select-option>
<a-select-option
v-for="item in organizationOptions"
:key="item.id"
:value="item.id"
>
{{ item.name }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="Admin Account">
<a-select
v-model:value="searchForm.adminAccId"
allow-clear
show-search
:filter-option="filterOption"
placeholder="Select Account"
style="width: 180px"
:options="allUserList"
></a-select>
</a-form-item>
<a-form-item>
<a-space>
<a-button type="primary" @click="handleSearch">Search</a-button>
<a-button @click="handleReset">Reset</a-button>
</a-space>
</a-form-item>
</a-form>
</a-card>
<a-card class="table-card" :bordered="false">
<div class="table-card__header">
<div class="table-card__title">Subscription Plan</div>
<a-button type="primary" @click="openCreate">New Subscription Plan</a-button>
</div>
<a-table
:data-source="tableData"
:columns="columns"
:loading="tableLoading"
row-key="id"
:pagination="{
showSizeChanger: true,
current: searchForm.page,
pageSize: searchForm.size,
total: searchForm.total,
showQuickJumper: true,
bordered: false
}"
>
<template #bodyCell="{ column, record }">
<template
v-if="
column.key === 'currentPeriodStart' || column.key === 'currentPeriodEnd'
"
>
{{ formatTime(record[column.key], 'YYYY-MM-DD hh:mm:ss') }}
</template>
<!-- <template v-if="column.key === 'organizationId'">
{{ organizationOptions.find(item => item.id === record[column.key]).name }}
</template> -->
<template v-if="column.key === 'status'">
<a-tag :color="statusColorMap[record.status]">
{{ statusLabelMap[record.status] }}
</a-tag>
</template>
<template v-if="column.key === 'adminAccId'">
{{ allUserList.find(item => item.value === record.adminAccId)?.label }}
</template>
<template v-else-if="column.key === 'actions'">
<a-space>
<a @click="openEdit(record)">Edit</a>
<a-popconfirm
title="Confirm to delete this subscription plan?"
ok-text="Confirm"
cancel-text="Cancel"
@confirm="removePlan(record.id)"
>
<a class="danger-text">Delete</a>
</a-popconfirm>
</a-space>
</template>
</template>
</a-table>
</a-card>
<div class="subscriptionPlanModal" ref="subscriptionPlanModal"></div>
<a-modal
class="subscriptionPlan_modal generalModel"
v-model:visible="modalVisible"
:footer="null"
:get-container="() => $refs.subscriptionPlanModal"
width="50%"
:maskClosable="false"
:centered="true"
:closable="false"
:mask="true"
wrapClassName="#app"
:keyboard="false"
destroy-on-close
>
<div class="generalModel_btn">
<div class="generalModel_closeIcon" @click.stop="cancelModal">
<svg
width="100%"
height="100%"
viewBox="0 0 46 46"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle cx="23" cy="23" r="23" fill="#000" fill-opacity="0.3" />
<rect
x="32.5063"
y="12"
width="3"
height="29"
rx="1.5"
transform="rotate(45 32.5063 12)"
fill="white"
/>
<rect
x="34.6274"
y="32.5059"
width="3"
height="29"
rx="1.5"
transform="rotate(135 34.6274 32.5059)"
fill="white"
/>
</svg>
</div>
</div>
<div class="modal_title_text">
<div>{{ modalTitle }}</div>
</div>
<div class="subscriptionPlan_center admin_page">
<div class="form_content">
<div class="admin_state_item">
<span>
Name:
<span>*</span>
</span>
<a-input
v-model:value="formState.name"
placeholder="Input the name"
style="width: 250px"
:disabled="isEditMode"
/>
</div>
<div class="admin_state_item">
<span>
Organization:
<span>*</span>
</span>
<a-select
v-model:value="formState.organizationId"
placeholder="Select the organization"
allow-clear
style="width: 250px"
@popupScroll="handleOrganizationScroll"
@select="handleOrganizationSelect"
@change="handleOrganizationChange"
:disabled="isEditMode"
>
<a-select-option value="ADD_ORGANIZATION" class="add-organization-option">
+ 添加组织
</a-select-option>
<a-select-option
v-for="item in organizationOptions"
:key="item.id"
:value="item.id"
>
{{ item.name }}
</a-select-option>
</a-select>
</div>
<div class="admin_state_item">
<span>
Admin Account:
<span>*</span>
</span>
<a-select
v-model:value="formState.adminAccId"
placeholder="Select the admin account"
allow-clear
show-search
:filter-option="filterOption"
style="width: 250px"
:options="allUserList"
></a-select>
</div>
<div class="admin_state_item">
<span>
Start Time:
<span>*</span>
</span>
<a-date-picker
v-model:value="formState.currentPeriodStart"
value-format="X"
style="width: 250px"
class="range_picker"
placeholder="Select the start time"
>
<template #suffixIcon>
<span class="icon iconfont range_picker_icon icon-rili"></span>
</template>
</a-date-picker>
</div>
<div class="admin_state_item">
<span>
End Time:
<span>*</span>
</span>
<a-date-picker
v-model:value="formState.currentPeriodEnd"
value-format="X"
style="width: 250px"
class="range_picker"
placeholder="Select the end time"
>
<template #suffixIcon>
<span class="icon iconfont range_picker_icon icon-rili"></span>
</template>
</a-date-picker>
</div>
<div class="admin_state_item">
<span>
Account Num:
<span>*</span>
</span>
<a-input-number
v-model:value="formState.accountNum"
:min="0"
style="width: 250px"
placeholder="Input the account number"
/>
</div>
<div class="admin_state_item">
<span>
Credit Limit:
<span>*</span>
</span>
<a-input-number
v-model:value="formState.creditLimit"
:min="0"
style="width: 250px"
placeholder="Input the credit limit"
/>
</div>
</div>
</div>
<div class="subscriptionPlan_btn admin_page">
<div class="admin_search_item" @click="cancelModal">Close</div>
<div class="admin_search_item" @click="handleSubmit">OK</div>
</div>
</a-modal>
<div class="organizationModal" ref="organizationModal"></div>
<a-modal
class="organization_modal"
v-model:visible="organizationModalVisible"
:footer="null"
:get-container="() => $refs.organizationModal"
:maskClosable="false"
:centered="true"
:mask="true"
wrapClassName="#app"
:keyboard="false"
destroy-on-close
>
<div class="modal_title_text">
<div>Create Organization</div>
</div>
<div class="subscriptionPlan_center admin_page">
<div class="form_content">
<div class="admin_state_item">
<span>
Name:
<span>*</span>
</span>
<a-input
v-model:value="organizationForm.name"
placeholder="Input the name"
style="width: 250px"
/>
</div>
<div class="admin_state_item">
<span>
Type:
<span>*</span>
</span>
<a-select
v-model:value="organizationForm.type"
placeholder="Select type"
style="width: 250px"
>
<a-select-option value="Enterprise">Enterprise</a-select-option>
<a-select-option value="Education">Education</a-select-option>
</a-select>
</div>
</div>
</div>
<div class="organization_footer">
<div class="footer_btn ant-btn ant-btn-primary" @click="cancelOrganizationModal">
Close
</div>
<div class="footer_btn ant-btn ant-btn-primary" @click="handleCreateOrganization">
OK
</div>
</div>
</a-modal>
</div>
</template>
<script setup lang="ts">
import { reactive, ref, onMounted, computed, nextTick } from 'vue'
import { message } from 'ant-design-vue'
import { Https } from '@/tool/https'
import { formatTime } from '@/tool/util'
import store from '@/store'
import type { FormInstance, Rule } from 'ant-design-vue/es/form'
type PlanStatus = 'active' | 'paused' | 'ended'
interface SubscriptionPlan {
id: number
name: string
currentPeriodStart: string
currentPeriodEnd: string
organizationId: string
adminAccId: string
status: PlanStatus
creditLimit: number
accountNum?: number
startStamp: number
endStamp: number
}
const searchForm = reactive({
name: '',
startTime: '',
endTime: '',
organizationId: undefined as string | undefined,
adminAccId: undefined as string | undefined,
id: '',
page: 1,
size: 10,
total: 0
})
const toSeconds = (dateStr: string) => Math.floor(new Date(dateStr).getTime() / 1000)
const tableData = ref<SubscriptionPlan[]>([])
const tableLoading = ref(false)
const modalVisible = ref(false)
const confirmLoading = ref(false)
const modalTitle = ref('New Subscription Plan')
const isEditMode = ref(false)
const formState = reactive({
name: '',
currentPeriodStart: '',
currentPeriodEnd: '',
organizationId: undefined as string | undefined,
adminAccId: undefined as string | undefined,
creditLimit: null as number | null,
accountNum: null as number | null
})
const organizationModalVisible = ref(false)
const organizationForm = reactive({
name: '',
type: undefined as string | undefined
})
const statusLabelMap: Record<PlanStatus, string> = {
active: 'Active',
paused: 'Paused',
ended: 'Ended'
}
const statusColorMap: Record<PlanStatus, string> = {
active: 'green',
paused: 'orange',
ended: 'red'
}
const columns = [
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'ID', dataIndex: 'id', key: 'id' },
{ title: 'Organization', dataIndex: 'organizationName', key: 'organizationName' },
{ title: 'Admin Account', dataIndex: 'adminAccId', key: 'adminAccId' },
{ title: 'Account Num', dataIndex: 'accountNum', key: 'accountNum' },
{
title: 'Start Time',
dataIndex: 'currentPeriodStart',
key: 'currentPeriodStart'
},
{
title: 'End Time',
dataIndex: 'currentPeriodEnd',
key: 'currentPeriodEnd'
},
{ title: 'Status', dataIndex: 'status', key: 'status' },
{ title: 'Credit Limit', dataIndex: 'creditLimit', key: 'creditLimit' },
{ title: 'Operations', key: 'actions', width: 160 }
]
onMounted(async () => {
await getOrganizationList()
await handleSearch()
})
const handleFetchTableData = async () => {
tableLoading.value = true
return Https.axiosPost(Https.httpUrls.searchAllSubscribePlan, searchForm)
.then(res => {
tableData.value = res.records.map(item => {
const organization = organizationOptions.value.find(
el => el.id === item.organizationId
) || { name: '' }
return {
...item,
organizationName: organization.name || ''
}
debugger
})
searchForm.total = res.total
})
.finally(() => {
tableLoading.value = false
})
}
const resetFormState = () => {
formState.name = ''
formState.currentPeriodStart = ''
formState.currentPeriodEnd = ''
formState.organizationId = undefined
formState.adminAccId = undefined
formState.creditLimit = null
formState.accountNum = null
}
const handleSearch = () => {
searchForm.page = 1
handleFetchTableData()
}
const handleReset = () => {
searchForm.name = ''
searchForm.startTime = ''
searchForm.endTime = ''
searchForm.organizationId = undefined
searchForm.adminAccId = undefined
searchForm.id = ''
handleSearch()
}
const allUserList = computed(() => {
return store.state.adminPage.allUserList
})
const openCreate = () => {
modalTitle.value = 'New Subscription Plan'
isEditMode.value = false
resetFormState()
modalVisible.value = true
}
const openEdit = (record: SubscriptionPlan) => {
modalTitle.value = 'Edit Subscription Plan'
isEditMode.value = true
formState.name = record.name
formState.currentPeriodStart = record.currentPeriodStart
formState.currentPeriodEnd = record.currentPeriodEnd
formState.organizationId = record.organizationId
formState.adminAccId = record.adminAccId
formState.creditLimit = record.creditLimit
formState.accountNum = (record as any).accountNum || null
modalVisible.value = true
}
const validateForm = (): boolean => {
interface FieldRule {
value: any
message: string
checkNull?: boolean
}
const requiredFields: FieldRule[] = [
{ value: formState.currentPeriodStart, message: 'Please select the start time' },
{ value: formState.currentPeriodEnd, message: 'Please select the end time' },
{ value: formState.adminAccId, message: 'Please select the admin account' },
{
value: formState.creditLimit,
message: 'Please input credit limit',
checkNull: true
},
{
value: formState.accountNum,
message: 'Please input account number',
checkNull: true
}
]
if (!isEditMode.value) {
requiredFields.push(
{ value: formState.name, message: 'Please input the name' },
{ value: formState.organizationId, message: 'Please select organization' }
)
}
for (const field of requiredFields) {
const isEmpty = field.checkNull
? field.value === null || field.value === undefined
: !field.value
if (isEmpty) {
message.warning(field.message)
return false
}
}
return true
}
const handleSubmit = async () => {
if (!validateForm()) return
confirmLoading.value = true
const params = {
...formState,
currentPeriodStart: Number(formState.currentPeriodStart),
currentPeriodEnd: Number(formState.currentPeriodEnd)
}
let res = null
try {
if (isEditMode.value) {
res = await Https.axiosPost(Https.httpUrls.updateSubscribePlan, params)
} else {
res = await Https.axiosPost(Https.httpUrls.createSubscribePlan, params)
}
message.success(
`${isEditMode.value ? 'Subscription plan updated' : 'Subscription plan created'}`
)
} catch (error: any) {
message.error(error.message)
console.error(error)
} finally {
confirmLoading.value = false
modalVisible.value = false
resetFormState()
isEditMode.value = false
handleSearch()
}
}
const cancelModal = () => {
modalVisible.value = false
resetFormState()
isEditMode.value = false
}
const removePlan = (id: number) => {
tableLoading.value = true
Https.axiosGet(Https.httpUrls.deleteSubscribePlan, { params: { id } })
.then(res => {
message.success('Subscription plan deleted')
handleReset()
})
.catch((error: any) => {
message.error(error.message)
console.error(error)
})
.finally(() => {
tableLoading.value = false
})
}
const organizationOptions = ref([])
const organizationParams = reactive({
page: 1,
size: 10,
total: 0
})
const organizationLoading = ref(false)
const getOrganizationList = async (isLoadMore = false) => {
if (organizationLoading.value) return
if (isLoadMore) {
const loaded = organizationParams.page * organizationParams.size
if (organizationParams.total && loaded >= organizationParams.total) return
organizationParams.page += 1
} else {
organizationParams.page = 1
organizationOptions.value = []
}
organizationLoading.value = true
try {
const rv: any = await Https.axiosPost(
Https.httpUrls.queryOrganization,
organizationParams
)
if (rv) {
organizationOptions.value = [...organizationOptions.value, ...(rv.records || [])]
organizationParams.total = rv.total || 0
}
} finally {
organizationLoading.value = false
}
}
const handleOrganizationScroll = (e: any) => {
const target = e?.target
if (!target) return
const nearBottom = target.scrollTop + target.clientHeight >= target.scrollHeight - 20
if (nearBottom) {
getOrganizationList(true)
}
}
const handleOrganizationSelect = (value: string) => {
if (value === 'ADD_ORGANIZATION') {
// 打开添加组织弹窗
organizationModalVisible.value = true
// 使用nextTick确保值被重置使其不被选中
nextTick(() => {
if (searchForm.organizationId === 'ADD_ORGANIZATION') {
searchForm.organizationId = undefined
}
if (formState.organizationId === 'ADD_ORGANIZATION') {
formState.organizationId = undefined
}
})
}
}
const handleOrganizationChange = (value: string) => {
// 如果change事件触发时值是"添加组织",立即重置
if (value === 'ADD_ORGANIZATION') {
nextTick(() => {
if (searchForm.organizationId === 'ADD_ORGANIZATION') {
searchForm.organizationId = undefined
}
if (formState.organizationId === 'ADD_ORGANIZATION') {
formState.organizationId = undefined
}
})
}
}
const cancelOrganizationModal = () => {
organizationModalVisible.value = false
organizationForm.name = ''
organizationForm.type = undefined
}
const handleCreateOrganization = async () => {
if (!organizationForm.name || !organizationForm.type) {
message.warning('Please fill in name and type')
return
}
try {
const res: any = await Https.axiosGet(Https.httpUrls.addOrganization, {
params: {
name: organizationForm.name,
type: organizationForm.type
}
})
message.success('Organization created successfully')
cancelOrganizationModal()
// 刷新组织列表
await getOrganizationList()
// 如果是在编辑/新建弹窗中,自动选择新创建的组织
if (modalVisible.value) {
const newOrgId = res?.id || res?.data?.id || res
if (newOrgId) {
formState.organizationId = String(newOrgId)
}
}
} catch (error: any) {
message.error(error.message || 'Failed to create organization')
console.error(error)
}
}
const filterOption = (input: string, option: any) => {
const label = option?.label ?? option?.children ?? option?.key?.label ?? ''
return String(label).toLowerCase().includes(input.toLowerCase())
}
</script>
<style lang="less" scoped>
.subscription-plan {
padding: 20px 24px 32px 0;
.search-card {
margin-bottom: 16px;
}
.table-card {
.table-card__header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
.table-card__title {
font-size: 18px;
font-weight: 500;
}
}
.danger-text {
color: #ff4d4f;
}
}
}
:deep(.subscriptionPlan_modal) {
.ant-modal-body {
height: calc(65rem * 1.2);
display: flex;
flex-direction: column;
padding: 2.5rem 3rem;
position: relative;
}
}
.subscriptionPlan_modal {
> .admin_state_item {
> span {
width: 15rem;
}
}
.modal_title_text {
margin-bottom: 2rem;
flex-shrink: 0;
}
.subscriptionPlan_center {
flex: 1;
overflow-y: auto;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
justify-content: center;
padding: 2rem 0;
}
.subscriptionPlan_btn {
display: flex;
flex-direction: row;
height: auto;
justify-content: flex-end;
padding: 1.5rem 0 0 0;
margin-top: auto;
flex-shrink: 0;
.admin_search_item {
margin-bottom: 0;
}
}
}
:deep(.search-form) {
column-gap: 2rem;
row-gap: 2rem;
.ant-select {
width: 100% !important;
}
}
:deep(.ant-select-dropdown) {
.add-organization-option {
color: #1890ff !important;
font-weight: 600;
background-color: #f0f7ff !important;
border-bottom: 1px solid #e6f4ff;
margin-bottom: 4px;
padding-bottom: 4px;
&:hover {
background-color: #e6f4ff !important;
}
}
}
:deep(.organization_modal) {
.ant-modal-body {
height: auto;
min-height: 300px;
display: flex;
flex-direction: column;
padding: 2rem 2.5rem;
position: relative;
}
.subscriptionPlan_center {
flex: 0 0 auto;
overflow: visible;
padding: 1rem 0;
min-height: auto;
}
.modal_title_text {
margin-bottom: 1.5rem;
}
}
.organization_footer {
display: flex;
justify-content: flex-end;
column-gap: 3rem;
.footer_btn {
border-radius: 3.3rem;
}
}
</style>

View File

@@ -61,7 +61,7 @@
<model
ref="model"
:key="positionKey"
@addDetail="addDetail"
@canvasReload="canvasReload"
@detailEdit="detailEdit"
@addSketch="()=>isEditPattern.value = ''"
@@ -78,16 +78,7 @@
<div class="item detailRight" :class="{canvas:isEditPattern.value}">
<div class="submit">
</div>
<div class="contentRight" v-if="currentDetailType === 'sketch' && !selectDetail?.newDetail?.[currentDetailType] && !selectDetail.sketchString && !isEditPattern.value">
<img
style="width: 100%; height: 100%;object-fit: contain;"
:src="
'/image/toolsGuide/' +
(locale == 'ENGLISH' ? 'detailEN' : 'detailCN') +
'.png'
" alt="">
</div>
<div class="contentRight" v-else-if="currentDetailType && !isEditPattern.value">
<div class="contentRight" v-if="currentDetailType && !isEditPattern.value">
<detailRight ref="detailRight"></detailRight>
<div class="btn"
v-show="
@@ -111,7 +102,7 @@
</div> -->
</div>
</div>
<addDetails ref="addDetails" @setSloganData="setSloganData"></addDetails>
</a-modal>
<div class="mark_loading" v-show="loadingShow">
<a-spin size="large" />
@@ -137,18 +128,17 @@ import { useI18n } from 'vue-i18n'
import addDetails from '@/component/Detail/addDetails.vue'
export default defineComponent({
components:{
detailLeft,model,detailRight,canvasBox,addDetails
detailLeft,model,detailRight,canvasBox
},
emits:['destroy'],
setup(props,{emit}) {
const store = useStore();
const {locale} = useI18n()
const detailDom = reactive({
model:null,
canvasBox,
detailRight,
detailLeft:null as any,
addDetails:null as any,
})
const userDetail = computed(()=>{
return store.state.UserHabit.userDetail
@@ -516,17 +506,6 @@ export default defineComponent({
sessionStorage.setItem('revocation', JSON.stringify(revocation));
sessionStorage.setItem('oppositeRevocation',JSON.stringify([]));
}
const addDetail = () =>{
let addDetails:any = detailDom.addDetails
addDetails.init(detailData.selectDetail,'')
}
const setSloganData = (data:any)=>{
detailData.selectDetail.sketchString = data
if(detailData.currentDetailType == 'sketch' && detailData.selectDetail?.newDetail?.sketch){
detailData.selectDetail.newDetail.sketch = null
}
}
onMounted(()=>{
window.addEventListener('resize', handleResize);
})
@@ -539,7 +518,6 @@ export default defineComponent({
})
return{
locale,
...toRefs(detailDom),
...toRefs(detailData),
closeModal,
@@ -553,8 +531,6 @@ export default defineComponent({
canvasReload,
modelOnLoad,
sketchSysToLibrary,
addDetail,
setSloganData,
}
},

View File

@@ -6,6 +6,7 @@
<element v-show="currentDetailType == 'element'"></element>
<accessory v-show="currentDetailType == 'accessory'"></accessory>
<models v-show="currentDetailType == 'models'"></models>
<addDetails ref="addDetails" @setSloganData="setSloganData"></addDetails>
</div>
</template>
<script lang="ts">
@@ -21,12 +22,12 @@ import color from './colorBox/index.vue'
import element from './element.vue'
import accessory from './accessory.vue'
import models from './models.vue'
import addDetails from '@/component/Detail/addDetails.vue'
export default defineComponent({
components:{
sketch,print,color,element,models,accessory
sketch,print,color,addDetails,element,models,accessory
},
emit:['addDetail'],
setup(props,{emit}) {
const store = useStore();
const detailData = reactive({
@@ -44,7 +45,14 @@ export default defineComponent({
sketch:null as any,
})
const addDetail = () =>{
emit('addDetail')
let addDetails:any = getDetailListDom.addDetails
addDetails.init(detailData.selectDetail,'')
}
const setSloganData = (data:any)=>{
detailData.selectDetail.sketchString = data
if(detailData.currentDetailType == 'sketch' && detailData.selectDetail?.newDetail?.sketch){
detailData.selectDetail.newDetail.sketch = null
}
}
const sketchSysToLibrary = ()=>{//系统sketch添加到library更新library
getDetailListDom.sketch.sketchSysToLibrary()
@@ -55,6 +63,7 @@ export default defineComponent({
...toRefs(getDetailListData),
...toRefs(getDetailListDom),
addDetail,
setSloganData,
sketchSysToLibrary,
}
},

View File

@@ -5,7 +5,7 @@
<!-- <img :src="selectDetail?.sketchString?selectDetail?.sketchString:selectDetail.path" alt=""> -->
<img :src="selectDetail.path" alt="">
<!-- <img :src="selectDetail.sketchString || selectDetail.path" alt=""> -->
<!-- <i :title="$t('DesignDetail.editSketchTitle')" class="fi fi-rs-pencil-paintbrush" @click.stop="openAddDetail"></i> -->
<i :title="$t('DesignDetail.editSketchTitle')" class="fi fi-rs-pencil-paintbrush" @click.stop="openAddDetail"></i>
</div>
<div class="select_sketch" v-else>
<div>

View File

@@ -15,7 +15,6 @@
<i class="icon iconfont icon-fanchehui" @click="oppositeRevocation"></i>
<!-- 编辑 -->
<i class="fi fi-rr-edit" :title="$t('DesignDetail.editTitle')" :class="{active:isEditPattern.value == 'canvasEditor','pointerEventsNone':!selectDetail?.id}" @click="showDesignImgDetail('canvasEditor')"></i>
<i class="fi fi-rs-pencil-paintbrush" :title="$t('DesignDetail.editSketchTitle')" :class="{'pointerEventsNone':!selectDetail?.id}" @click="()=>$emit('addDetail')"></i>
<i class="icon iconfont icon-clothes" :title="$t('Canvas.editFrontBack')" style="font-size: 3.2rem;" @click="showDesignImgDetail('redGreenExample')" :class="{active:isEditPattern.value == 'redGreenExample','pointerEventsNone':!selectDetail?.id}"></i>
<!-- <i @click="showDesignImgDetail('redGreenExample')" :class="{active:isEditPattern.value == 'redGreenExample','pointerEventsNone':!selectDetail?.id}">
@@ -51,7 +50,7 @@ export default defineComponent({
components:{
position,modelNav
},
emits:['detailEdit','canvasReload','addSketch','revocation','oppositeRevocation','modelOnLoad','sketchSysToLibrary','addDetail'],
emits:['detailEdit','canvasReload','addSketch','revocation','oppositeRevocation','modelOnLoad','sketchSysToLibrary'],
setup(props,{emit}) {
const {t} = useI18n()
const store = useStore();

View File

@@ -34,8 +34,8 @@
</div>
</div>
<div class="layout_centent" :class="{active:flex_direction}" id="layoutCentent">
<div v-for="item,index in layoutList" :key="item" :class="moodbClassName[index]" class="modal_imgItem" v-layout="item" @mousedown="setpitch(item,index)" @touchstart="setpitch(item,index)" ref="content" :style="{'background-image':`url(${item.imgUrl})`,'transform':`scale(${item.zoom?item.zoom:1}) rotateZ(${item.angle?item.angle:0}deg)`}">
<!-- <img crossOrigin="anonymous" :src="item.imgUrl" :style="{'transform':`translate(-50%, -50%) scale(${item.zoom?item.zoom:1}) rotateZ(${item.angle?item.angle:0}deg)`}" draggable="false" :class="moodbClassName[index]" v-modelImg> -->
<div v-for="item,index in layoutList" :key="item" :class="moodbClassName[index]" class="modal_imgItem" v-layout="item" @mousedown="setpitch(item,index)" @touchstart="setpitch(item,index)" ref="content" >
<img crossOrigin="anonymous" :src="item.imgUrl" :style="{'transform':`translate(-50%, -50%) scale(${item.zoom?item.zoom:1}) rotateZ(${item.angle?item.angle:0}deg)`}" draggable="false" :class="moodbClassName[index]" v-modelImg>
<ul v-show="item.setPitch" class="layout_btn" >
<li class="layout_btn_top" v-compile.stop="'top'"></li>
<li class="layout_btn_bottom" v-compile.stop="'bottom'"></li>
@@ -736,7 +736,6 @@ export default defineComponent({
setmoodb(item:any){
this.moodbClassName = item
this.$emit('setmoodbClass',this.moodbClassName)
this.styleObj.class = this.moodbClassName
if(this.content){
for (item of (this.content as any)) {
item.classList.remove('active')
@@ -773,7 +772,7 @@ export default defineComponent({
initDomStyle(){
nextTick(()=>{
this.content.forEach((item:any,index:any) => {
if(this.styleObj.domStyle[index]?.left){
if(this.styleObj.domStyle[index]){
item.classList.add('active')
this.initStyle(item,this.styleObj.domStyle[index])
}
@@ -795,7 +794,7 @@ export default defineComponent({
})
},
initStyle(dom:any,style:any){
if(!style || !dom)return
if(!style)return
for (const [property, value] of Object.entries(style)) {
dom.style.setProperty(property, value);
@@ -807,7 +806,7 @@ export default defineComponent({
this.styleObj.domStyle.push(this.setStyle(item.style))
this.domObj.dom.forEach((domName:any,index:any) => {
let style = this.domObj.domStyle[index]
let dom = item.querySelector(domName) || item
let dom = item.querySelector(domName)
this.styleObj[style].push(this.setStyle(dom.style))
})
});
@@ -841,6 +840,7 @@ export default defineComponent({
let config:any = {headers:{'Content-Type':'multipart/form-data','Accept':'*/*' }}
Https.axiosPost(Https.httpUrls.elementUpload,param,config)
.then((rv: any) => {
// console.log(rv);
rv.imgUrl = rv.url
this.layout = false
this.loadingShow = false
@@ -1062,12 +1062,27 @@ export default defineComponent({
// height: 100%;
// }
overflow: hidden;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
&.active{
position: absolute;
}
img{
// object-fit: cover;
// width: 100%;
// height: 100%;
pointer-events: none;
float: left;
user-select:none;
-webkit-user-drag: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%) scale(1);
}
::selection {
// background: rgba(0,0,0,0);
// background: yellow;
}
}
}
.wh1{

View File

@@ -19,8 +19,7 @@
<div class="generalModel_closeIcon" @click.stop="cancelDsign()">
<!-- <i class="fi fi-rr-cross-small"></i> -->
<svg
width="100%"
height="100%"
width="100%" height="100%"
viewBox="0 0 46 46"
fill="none"
xmlns="http://www.w3.org/2000/svg"
@@ -50,32 +49,20 @@
<div class="renewContent">
<div class="left">
<div class="video">
<video
autoplay
loop
muted
playsinline
src="@/assets/images/icon/paymentVideo.mp4"
></video>
<video autoplay loop muted playsinline src="@/assets/images/icon/paymentVideo.mp4"></video>
<div class="mask"></div>
</div>
<div class="title">{{ $t('Renew.Strengths') }}</div>
<div class="title">{{ $t("Renew.Strengths") }}</div>
<div class="content">
<div class="benefitsItem">
<div class="describe">
<div class="icon">
<img src="@/assets/images/icon/paymentIntroduce1.png" alt="" />
<img src="@/assets/images/icon/paymentIntroduce1.png" alt="">
</div>
<div class="text">
<p class="title">
{{ $t('Renew.StrengthsTitle1') }}
<br />
{{ $t('Renew.StrengthsTitle1_1') }}
</p>
<p class="title">{{ $t("Renew.StrengthsTitle1") }}<br>{{ $t("Renew.StrengthsTitle1_1") }}</p>
<p class="info">
{{ $t('Renew.StrengthsInfo1') }}
<br />
{{ $t('Renew.StrengthsInfo1_1') }}
{{ $t("Renew.StrengthsInfo1") }}<br>{{ $t("Renew.StrengthsInfo1_1") }}
</p>
</div>
</div>
@@ -83,18 +70,12 @@
<div class="benefitsItem">
<div class="describe">
<div class="icon">
<img src="@/assets/images/icon/paymentIntroduce2.png" alt="" />
<img src="@/assets/images/icon/paymentIntroduce2.png" alt="">
</div>
<div class="text">
<p class="title">
{{ $t('Renew.StrengthsTitle2') }}
<br />
{{ $t('Renew.StrengthsTitle2_1') }}
</p>
<p class="title">{{ $t("Renew.StrengthsTitle2") }}<br>{{ $t("Renew.StrengthsTitle2_1") }}</p>
<p class="info">
{{ $t('Renew.StrengthsInfo2') }}
<br />
{{ $t('Renew.StrengthsInfo2_1') }}
{{ $t("Renew.StrengthsInfo2") }}<br>{{ $t("Renew.StrengthsInfo2_1") }}
</p>
</div>
</div>
@@ -102,21 +83,13 @@
<div class="benefitsItem">
<div class="describe">
<div class="icon">
<img src="@/assets/images/icon/paymentIntroduce3.png" alt="" />
<img src="@/assets/images/icon/paymentIntroduce3.png" alt="">
</div>
<div class="text">
<p class="title"></p>
<p class="title">
{{ $t('Renew.StrengthsTitle3') }}
<br />
{{ $t('Renew.StrengthsTitle3_1') }}
</p>
<p class="title">{{ $t("Renew.StrengthsTitle3") }}<br>{{ $t("Renew.StrengthsTitle3_1") }}</p>
<p class="info">
{{ $t('Renew.StrengthsInfo3') }}
<br />
{{ $t('Renew.StrengthsInfo3_1') }}
<br />
{{ $t('Renew.StrengthsInfo3_2') }}
{{ $t("Renew.StrengthsInfo3") }}<br>{{ $t("Renew.StrengthsInfo3_1") }}<br>{{ $t("Renew.StrengthsInfo3_2") }}
</p>
</div>
</div>
@@ -124,18 +97,12 @@
<div class="benefitsItem">
<div class="describe">
<div class="icon">
<img src="@/assets/images/icon/paymentIntroduce4.png" alt="" />
<img src="@/assets/images/icon/paymentIntroduce4.png" alt="">
</div>
<div class="text">
<p class="title">
{{ $t('Renew.StrengthsTitle4') }}
<br />
{{ $t('Renew.StrengthsTitle4_1') }}
</p>
<p class="title">{{ $t("Renew.StrengthsTitle4") }}<br>{{ $t("Renew.StrengthsTitle4_1") }}</p>
<p class="info">
{{ $t('Renew.StrengthsInfo4') }}
<br />
{{ $t('Renew.StrengthsInfo4_1') }}
{{ $t("Renew.StrengthsInfo4") }}<br>{{ $t("Renew.StrengthsInfo4_1") }}
</p>
</div>
</div>
@@ -144,7 +111,7 @@
</div>
<div class="right">
<div class="title">
{{ $t('Renew.title') }}
{{ $t("Renew.title") }}
</div>
<!-- <div class="info">{{ $t("Renew.unlimited") }}</div> -->
<div class="content">
@@ -152,31 +119,36 @@
class="productItem"
:class="{
active: item.price == current.price,
sellWell: item.sellWell
sellWell: item.sellWell,
}"
v-for="item in personage"
:key="item.price"
@click="setPromotionData(item)"
>
<div class="popular" v-show="item.sellWell">
{{ $t('Renew.MOSTPOPULAR') }}
</div>
<div class="popular" v-show="item.sellWell">{{ $t("Renew.MOSTPOPULAR") }}</div>
<div class="priceBox">
<div class="left">
<p class="productType">1 {{ item.type.label }}</p>
<p class="price">HK $ {{ item.price }}</p>
<p class="price">${{ item.price }}</p>
</div>
<div class="right">
<div class="promotion">
<div class="succeed" v-show="item.promotionData.error == 'true'">
<div
class="succeed"
v-show="item.promotionData.error == 'true'"
>
{{ item.promotionData.code }}
<i class="fi fi-sr-times-hexagon" @click="clearPromotionCode"></i>
<i
class="fi fi-sr-times-hexagon"
@click="clearPromotionCode"
></i>
</div>
<div
class="input"
@click.stop
v-show="
!item.promotionData.error || item.promotionData.error == 'false'
!item.promotionData.error ||
item.promotionData.error == 'false'
"
>
<input
@@ -184,11 +156,14 @@
:placeholder="$t('Renew.promotionCode')"
v-model="item.promotionData.code"
/>
<div class="apply-btn" @click="examine(item)">
{{ $t('Renew.use') }}
<div style="cursor: pointer; background-color: #000; font-size: 1.2rem; color: #fff; padding: 0 .5rem;" @click="examine(item)">
{{ $t("Renew.use") }}
</div>
</div>
<div class="error" v-show="item.promotionData.error == 'false'">
<div
class="error"
v-show="item.promotionData.error == 'false'"
>
{{ item.promotionData.str }}
</div>
</div>
@@ -206,7 +181,7 @@
<div class="payment">
<div class="allocation">
<div class="selectType">
<div class="text">{{ $t('Renew.Payment') }}:</div>
<div class="text">{{ $t("Renew.Payment") }}:</div>
<label>
<input
name="payment"
@@ -215,7 +190,7 @@
v-model="PaymentType"
@change="setPaymentType('CreditCard')"
/>
{{ $t('Renew.CreditCard') }}
{{ $t("Renew.CreditCard") }}
</label>
<label>
<input
@@ -225,47 +200,43 @@
v-model="PaymentType"
@change="setPaymentType('Alipay')"
/>
{{ $t('Renew.Alipay') }}
{{ $t("Renew.Alipay") }}
</label>
</div>
</div>
<div class="gallery_btn gallery_btn_radius" @click="payment">
{{ $t('upgradePlan.Continue') }}
{{ $t("upgradePlan.Continue") }}
</div>
<div class="payMethod_payAffirm_clause" ref="labelDisclaimer">
<label>
<!-- <input type="checkbox" v-model="clause" /> -->
<span class="generalModelDescription">
{{ $t('upgradePlan.policy') }}
<span class="generalModelDescription"
>{{ $t("upgradePlan.policy")}}
<a
href="https://code-create.com.hk/aida-terms-and-conditions/"
target="_blank"
>
{{ $t('upgradePlan.policy1') }}
target="_blank">
{{ $t("upgradePlan.policy1") }}
</a>
&
<a
href="https://code-create.com.hk/aida-subscription-agreement/"
target="_blank"
>
{{ $t('upgradePlan.policy2') }}
target="_blank">
{{ $t("upgradePlan.policy2") }}
</a>
<!-- . * -->
</span>
</span
>
</label>
<label class="secure">
<span>
<i class="fi fi-rr-shield-check"></i>
Pay safe & secure
</span>
<span><i class="fi fi-rr-shield-check"></i>Pay safe & secure</span>
</label>
<label class="payIcon">
<img class="stripe" src="@/assets/images/icon/stripe.svg" alt="" />
<img class="alipay" src="@/assets/images/icon/alipay.svg" alt="" />
<img class="alipay" src="@/assets/images/icon/jcbPay.svg" alt="" />
<img class="alipay" src="@/assets/images/icon/mastercardPay.svg" alt="" />
<img class="alipay" src="@/assets/images/icon/yinlianPay.svg" alt="" />
<img class="alipay" src="@/assets/images/icon/visaPay.svg" alt="" />
<img class="stripe" src="@/assets/images/icon/stripe.svg" alt="">
<img class="alipay" src="@/assets/images/icon/alipay.svg" alt="">
<img class="alipay" src="@/assets/images/icon/jcbPay.svg" alt="">
<img class="alipay" src="@/assets/images/icon/mastercardPay.svg" alt="">
<img class="alipay" src="@/assets/images/icon/yinlianPay.svg" alt="">
<img class="alipay" src="@/assets/images/icon/visaPay.svg" alt="">
</label>
</div>
<!-- <div class="paySecure">
@@ -279,104 +250,101 @@
<a-spin size="large" />
</div>
<div class="mark_loading" v-show="isShowMark" state="true">
<div class="mark_loading_title">{{ $t('upgradePlan.completed') }}</div>
<div class="mark_loading_intro">{{ $t('upgradePlan.hint') }}</div>
<div class="mark_loading_title">{{ $t("upgradePlan.completed") }}</div>
<div class="mark_loading_intro">{{ $t("upgradePlan.hint") }}</div>
<div class="mark_loading_title_box">
<div class="mark_loading_btn mark_loading_btn2" @click="setPaidBack">
{{ $t('upgradePlan.Back') }}
{{ $t("upgradePlan.Back") }}
</div>
<div class="mark_loading_btn" @click="completePayment">OK</div>
</div>
</div>
</a-modal>
<payMethod ref="payMethod" @completePayment="cancelDsign" type="renew"></payMethod>
</template>
<payMethod
ref="payMethod"
@completePayment="cancelDsign"
type="renew"
></payMethod>
</template>
<script lang="ts">
import {
defineComponent,
computed,
reactive,
toRefs,
onMounted,
onBeforeUnmount
} from 'vue'
import { message } from 'ant-design-vue'
import payMethod from '@/component/Pay/payMethod.vue'
import { useStore } from 'vuex'
import { useI18n } from 'vue-i18n'
import { Https } from '@/tool/https'
import md5 from 'md5'
export default defineComponent({
<script lang="ts">
import { defineComponent, computed, reactive, toRefs, onMounted, onBeforeUnmount } from "vue";
import { message } from "ant-design-vue";
import payMethod from "@/component/Pay/payMethod.vue";
import { useStore } from "vuex";
import { useI18n } from "vue-i18n";
import { Https } from "@/tool/https";
import md5 from "md5";
export default defineComponent({
components: {
payMethod
payMethod,
},
setup() {
const store = useStore()
const { t } = useI18n()
const store = useStore();
const { t } = useI18n();
let renew = reactive({
renewModel: false,
renewModelMask: true,
pageWidth: '50%'
})
pageWidth: "50%",
});
let payMethodData = reactive({
clause: false,
labelDisclaimer: null as any,
newWindow: null as any,
isShowMark: false,
isShowMark_: false
})
isShowMark_: false,
});
let renewData = reactive({
personage: [
{
price: '100',
price: "100",
sellWell: true,
activity: false, //活动打折
type: {
value: 'EcoMonth',
label: computed(() => t('Renew.Monthly'))
value: "EcoMonth",
label: computed(()=>t("Renew.Monthly")),
},
// PaymentType: "CreditCard",
promotionData: {
code: '',
error: '',
str: '',
price: ''
}
code: "",
error: "",
str: "",
price: "",
},
},
{
price: '500',
price: "500",
sellWell: false,
activity: false, //活动打折
type: {
value: 'Month',
label: computed(() => t('Renew.Monthly'))
value: "Month",
label: computed(()=>t("Renew.Monthly")),
},
// PaymentType: "CreditCard",
promotionData: {
code: '',
error: '',
str: '',
price: ''
}
code: "",
error: "",
str: "",
price: "",
},
},
{
price: '5,000',
price: "5,000",
sellWell: false,
activity: false, //活动打折
typeValue: 'year',
typeValue: "year",
type: {
value: 'Year',
label: computed(() => t('Renew.Yearly'))
value: "Year",
label: computed(()=>t("Renew.Yearly")),
},
// PaymentType: "CreditCard",
promotionData: {
code: '',
error: '',
str: '',
price: ''
}
}
code: "",
error: "",
str: "",
price: "",
},
},
],
// personage:computed(()=>{
// return {
@@ -397,55 +365,55 @@ export default defineComponent({
// }),
firm: computed(() => {
return {
title: 'Education Edition',
title: "Education Edition",
price: {
year: '500'
year: "500",
},
unit: {
year: 'HKD / Year'
year: "HKD / Year",
},
type: 'year',
type: "year",
autoRenewal: {
text: t('Renew.automatically'),
value: true
text: t("Renew.automatically"),
value: true,
},
typeList: ['year'],
info: 'Customised plan'
}
typeList: ["year"],
info: "Customised plan",
};
}),
education: computed(() => {
return {
title: 'Enterprise Edition',
title: "Enterprise Edition",
price: {
year: '500'
year: "500",
},
unit: {
year: 'HKD / Year'
year: "HKD / Year",
},
type: 'year',
type: "year",
autoRenewal: {
text: t('Renew.automatically'),
value: true
text: t("Renew.automatically"),
value: true,
},
typeList: ['year'],
info: 'Customised plan'
}
typeList: ["year"],
info: "Customised plan",
};
}),
current: {} as any,
payMethod: null as any,
PaymentType: 'CreditCard'
})
PaymentType: "CreditCard",
});
const init = () => {
renew.renewModel = true
renewData.current = renewData.personage[1]
}
renew.renewModel = true;
renewData.current = renewData.personage[1];
};
const cancelDsign = () => {
renew.renewModel = false
renew.renewModel = false;
store.dispatch('getUserDetail')
}
};
const setPaymentType = (str: any) => {
renewData.PaymentType = str
}
renewData.PaymentType = str;
};
const payment = () => {
// if (!payMethodData.clause) {
// let labelDisclaimer: any = payMethodData.labelDisclaimer;
@@ -457,92 +425,104 @@ export default defineComponent({
// }
// return;
// }
if (!renewData.PaymentType) return message.info(t('Renew.PleaseSelectPayment'))
let url = window.location.origin + '/paySucceed'
if (!renewData.PaymentType)
return message.info(t("Renew.PleaseSelectPayment"));
let url = window.location.origin + "/paySucceed";
let data = {
autoRenewal: renewData.PaymentType != 'Alipay', //false为不自动续费
productName: 'Subscription',
autoRenewal: renewData.PaymentType != "Alipay", //false为不自动续费
productName: "Subscription",
quantity: 1,
returnUrl: url,
subscribeType: renewData.current.type.value, //yearly为年费monthly为月费
wallet: 'ALIPAYHK',
promotionCode: renewData.current.promotionData.code
}
let httpsUrl = Https.httpUrls.payStripe
payMethodData.isShowMark_ = true
wallet: "ALIPAYHK",
promotionCode: renewData.current.promotionData.code,
};
let httpsUrl = Https.httpUrls.payStripe;
payMethodData.isShowMark_ = true;
Https.axiosPost(httpsUrl, data)
.then((rv: any) => {
var width = 800
var height = 600
var left = (screen.width - width) / 2
var top = (screen.height - height) / 2
var width = 800;
var height = 600;
var left = (screen.width - width) / 2;
var top = (screen.height - height) / 2;
payMethodData.newWindow = window.open(
'',
'_blank',
'width=' + width + ', height=' + height + ', left=' + left + ', top=' + top
)
let herf = rv
"",
"_blank",
"width=" +
width +
", height=" +
height +
", left=" +
left +
", top=" +
top
);
let herf = rv;
if (payMethodData.newWindow) {
payMethodData.newWindow.location.href = herf
payMethodData.newWindow.location.href = herf;
} else {
// window.open(herf, '_blank');
window.location.href = herf
window.location.href = herf;
}
payMethodData.newWindow = null
payMethodData.isShowMark = true
payMethodData.isShowMark_ = false
})
.catch(res => {
payMethodData.isShowMark_ = false
payMethodData.newWindow = null;
payMethodData.isShowMark = true;
payMethodData.isShowMark_ = false;
})
.catch((res) => {
payMethodData.isShowMark_ = false;
});
// renewData.payMethod.init(data)
}
};
const setPaidBack = () => {
payMethod.payMethodModel = false
payMethodData.isShowMark = false
payMethodData.clause = false
}
payMethod.payMethodModel = false;
payMethodData.isShowMark = false;
payMethodData.clause = false;
};
const completePayment = () => {
renew.renewModel = false
setPaidBack()
}
renew.renewModel = false;
setPaidBack();
};
const examine = (item: any) => {
// renewData.promotionData.error
let price = item?.price
const normalNumber = Number(price.replace(/,/g, ''))
let price = item?.price;
const normalNumber = Number(price.replace(/,/g, ""));
if (!item.promotionData.code) {
return
return;
}
let data = {
promotionCode: item.promotionData.code,
price: normalNumber
}
Https.axiosGet(Https.httpUrls.checkCoupon, { params: data }).then((rv: any) => {
price: normalNumber,
};
Https.axiosGet(Https.httpUrls.checkCoupon, { params: data }).then(
(rv: any) => {
if (rv) {
renewData.personage.forEach((personageItem: any) => {
if (personageItem.price == item.price) {
if (rv.status == 'valid') {
item.promotionData.error = 'true'
item.promotionData.price = Number(rv.discountedPrice).toLocaleString()
if (rv.status == "valid") {
item.promotionData.error = "true";
item.promotionData.price = Number(
rv.discountedPrice
).toLocaleString();
} else {
item.promotionData.error = 'false'
item.promotionData.str = rv.message
item.promotionData.error = "false";
item.promotionData.str = rv.message;
}
}
})
});
} else {
}
})
}
);
};
const clearPromotionCode = () => {
renewData.current.promotionData.error = ''
renewData.current.promotionData.code = ''
renewData.current.promotionData.price = ''
}
renewData.current.promotionData.error = "";
renewData.current.promotionData.code = "";
renewData.current.promotionData.price = "";
};
const setPromotionData = (item: any) => {
renewData.current = item
}
renewData.current = item;
};
return {
store,
...toRefs(renew),
@@ -556,21 +536,21 @@ export default defineComponent({
completePayment,
examine,
clearPromotionCode,
setPromotionData
}
setPromotionData,
};
},
data() {
return {}
return {};
},
methods: {
turnToWindow(url: any) {
window.open(url)
}
}
})
</script>
<style lang="less" scoped>
.renew {
window.open(url);
},
},
});
</script>
<style lang="less" scoped>
.renew {
:deep(.ant-modal-body) {
padding: 0;
}
@@ -610,24 +590,24 @@ export default defineComponent({
position: relative;
display: flex;
flex-direction: column;
> .video {
> .video{
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
> video {
> video{
width: 100%;
height: 100%;
object-fit: cover;
}
> .mask {
> .mask{
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
background: rgba(0, 0, 0, 0.5);
background: rgba(0,0,0,.5);
}
}
@@ -699,11 +679,11 @@ export default defineComponent({
margin-bottom: 1rem;
border-radius: 1rem;
overflow: hidden;
border: 1.5px solid #e7ebff;
border: 1.5px solid #E7EBFF;
cursor: pointer;
> .popular {
background: #1b223c;
background: #1B223C;
font-weight: 600;
display: flex;
justify-content: center;
@@ -765,31 +745,15 @@ export default defineComponent({
display: flex;
align-items: center;
border-radius: 2rem;
border: 1.5px solid rgb(216, 218, 220);
border: 2px solid #000;
overflow: hidden;
padding: 0 1rem;
background-color: #fff;
input {
border: none;
height: 3rem;
width: 10rem;
font-size: 1.2rem;
background: rgba(0, 0, 0, 0);
&::placeholder {
color: #c4c4c4;
}
}
.apply-btn {
cursor: pointer;
background-color: rgb(27, 34, 60);
font-size: 0.8rem;
color: #fff;
width: 3.3rem;
height: 1.4rem;
line-height: 1.4rem;
display: flex;
align-items: center;
justify-content: center;
}
}
> .error {
@@ -804,11 +768,11 @@ export default defineComponent({
}
}
}
&.active,
&:hover {
&.active,&:hover {
// 40% opacity
background: rgba(231, 235, 255, 0.4);
// border: 2px solid #0ea982;
}
&.sellWell {
// border: 2px solid #0ea982;
@@ -846,15 +810,10 @@ export default defineComponent({
> .gallery_btn {
width: 100%;
margin: 2rem 0;
margin-bottom: 0.5rem;
margin-bottom: .5rem;
margin-top: 1rem;
background: #1b223c;
background: #1B223C;
color: #fff;
// width: 41.8rem;
height: 4rem;
box-sizing: border-box;
line-height: 4rem;
border-radius: 0.6rem;
}
> .payMethod_payAffirm_clause {
text-align: center;
@@ -876,27 +835,27 @@ export default defineComponent({
}
}
}
> .secure {
> .secure{
border: 1px solid #ededed;
background: #f1fbf9;
color: #1cb36c;
padding: 0.4rem 0.8rem;
border-radius: 0.5rem;
padding: .4rem .8rem;
border-radius: .5rem;
margin-top: 4rem;
> span {
> span{
display: flex;
align-items: center;
}
i {
i{
display: flex;
margin-right: 0.5rem;
margin-right: .5rem;
}
}
> .payIcon {
> .payIcon{
height: 2rem;
margin-top: 1rem;
img {
margin: 0 0.3rem;
img{
margin: 0 .3rem;
height: 100%;
}
}
@@ -992,5 +951,6 @@ export default defineComponent({
background: rgba(0, 0, 0, 0);
}
}
}
</style>
}
</style>

View File

@@ -6,7 +6,7 @@
<!-- <div class="icon" @click="toGmailLogin"> -->
<div class="icon">
<img src="@/assets/images/loginPage/gmailIcon.svg" alt="">
<span>{{ displayText }}</span>
<span>{{ $props.text }}</span>
</div>
</div>
</template>
@@ -21,7 +21,7 @@
props: {
text: {
type: String,
default: ''
default: 'Sign in with Google'
}
},
setup(props, { emit }) {
@@ -108,9 +108,6 @@
const toGmailLogin = ()=>{
message.info(t('account.canNotUtilize'))
}
const displayText = computed(() => {
return props.text || t('Login.LoginWithGoogle')
})
onBeforeUnmount(()=>{
var existingScript = document.querySelector(`script[src="${data.scriptSrc}"]`);
if(existingScript){
@@ -123,7 +120,6 @@
})
return {
toGmailLogin,
displayText,
}
},
})

View File

@@ -553,14 +553,13 @@ export default defineComponent({
loginType: "EMAIL",
userId: this.userId,
};
this.store.commit('set_loading', true)
this.$emit('update:isMask',true)
Https.axiosPost(Https.httpUrls.accountLogin, data)
.then((rv: any) => {
this.setSuccessLogin(rv);
this.store.commit('set_loading', false)
})
.catch((res) => {
this.store.commit('set_loading', false)
this.$emit('update:isMask',false)
});
},1000)
},

View File

@@ -2,7 +2,7 @@
<div class="Container">
<div class="icon" @click="openWeiXinModel">
<img src="@/assets/images/loginPage/weiXinIcon.svg" alt="" />
<span>{{ displayText }}</span>
<span>{{ $props.text }}</span>
</div>
<weiXinModel ref="weiXinModel"></weiXinModel>
</div>
@@ -18,7 +18,6 @@ import {
toRefs,
} from "vue";
import weiXinModel from "./weiXinModel.vue";
import { useI18n } from 'vue-i18n'
export default defineComponent({
name: "login",
components: {
@@ -27,25 +26,20 @@ export default defineComponent({
props: {
text: {
type: String,
default: ''
default: "Sign in with Wechat",
},
},
setup(props) {
setup() {
let weiXinDom = reactive({
weiXinModel: null,
});
const { t } = useI18n()
const openWeiXinModel = () => {
weiXinDom.weiXinModel.init();
};
const displayText = computed(() => {
return props.text || t('Login.LoginWithWechat')
})
onMounted(() => {});
return {
...toRefs(weiXinDom),
openWeiXinModel,
displayText,
};
},
});

View File

@@ -113,8 +113,8 @@
<img v-for="item in scaleImageData?.designPythonOutfitList" v-lazy="item.designUrl">
</div>
</div>
<!-- <div v-if="userDetail.systemList.indexOf(1) > -1 && scaleImageData.isMine != 1 && scaleImageData.selected != 1 && scaleImageData.openSource != 0" class="started_btn" @click="setChoose" >{{$t('newScaleImage.SecondaryCreation')}}</div> -->
<div v-if="userDetail.systemList.indexOf(1) > -1 && scaleImageData.openSource != 0" class="started_btn" @click="setChoose" >{{$t('newScaleImage.SecondaryCreation')}}</div>
<div v-if="userDetail.systemList.indexOf(1) > -1 && scaleImageData.isMine != 1 && scaleImageData.selected != 1 && scaleImageData.openSource != 0" class="started_btn" @click="setChoose" >{{$t('newScaleImage.SecondaryCreation')}}</div>
<!-- <div v-if="systemUser.value == 1 && scaleImageData.isMine != 1 && scaleImageData.selected != 1" class="started_btn" @click="setChoose" :title="systemUser.value != 1?$t('newScaleImage.jsContent1'): scaleImageData.openSource == 0?$t('newScaleImage.jsContent2'):''" :class="{active:systemUser.value != 1?true:scaleImageData.openSource == 0}">{{$t('newScaleImage.SecondaryCreation')}}</div> -->
</div>
<div v-else class="newScaleImage_right_content_generate">
<div class="scaleImage_chunk_item content_left_generate_item">
@@ -458,7 +458,6 @@ export default defineComponent({
message.info(t('newScaleImage.jsContent2'))
return
}
store.state.Workspace.cachedRoutes = [];
let id = await getWorks(imgData.scaleImageData.id)
await router.push(`/home/history/${id}`)
store.commit('setChooseIsDesign',false)

View File

@@ -132,8 +132,8 @@
</div>
<div class="modal_img_max">
<div v-if="!modalImg[0]?.id" class="modal_img" id="modal_img" :class="{active:flex_direction}">
<!-- <div class="modal_img" id="modal_img" :class="{active:flex_direction}"> -->
<div v-for="item,index in layoutList" :class="[moodb_className[index]]" :style="{'background-image':`url(${item.imgUrl})`}" class="modal_imgItem">
<div v-for="item,index in layoutList" :class="[moodb_className[index]]" class="modal_imgItem">
<img :src="item.imgUrl" v-modelImg>
</div>
</div>
<div v-else class="modal_img">
@@ -244,6 +244,30 @@ export default defineComponent({
this.token = getCookie("token") || "";
this.uploadUrl = getUploadUrl();
},
directives:{
modelImg:{
mounted(el) {
let parentNode = el.parentNode
if(parentNode.offsetHeight >= parentNode.offsetWidth){
el.style.height = 100+'%'
el.style.width = 'auto'
}else{
el.style.width = 100+'%'
el.style.height = 'auto'
}
},
updated (el) {
let parentNode = el.parentNode
if(parentNode.offsetHeight >= parentNode.offsetWidth){
el.style.height = 100+'%'
el.style.width = 'auto'
}else{
el.style.width = 100+'%'
el.style.height = 'auto'
}
}
}
},
methods: {
open(num: Number) {
this.openClick = num;
@@ -421,7 +445,7 @@ export default defineComponent({
}
}
this.edieShow = true
if(this.moodb_[arr.length-1].length == 1){
if(this.moodb_[arr.length-1].length == 2){
this.moodb_className = this.moodb_[arr.length-1][0]
}else{
this.moodb_className = this.moodb_[arr.length-1][random]
@@ -604,7 +628,6 @@ export default defineComponent({
height: calc(5rem*1.2);
overflow-x: hidden;
display: flex;
&.modal_img::-webkit-scrollbar {
display: none;
}
@@ -683,9 +706,15 @@ export default defineComponent({
position: relative;
overflow: hidden;
text-align: center;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
img{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
// float: left;
// user-select:none;
// -webkit-user-drag: none;
}
}
.wh1{
width: 23%;

View File

@@ -242,16 +242,7 @@
</div>
</div>
<div class="prompt-input-container" v-show="!showMotion">
<div class="title">
<span>{{ $t('ProductImg.Prompt') }}</span>
<SvgIcon
class="cursor-icon"
@click="handleNavigateHelp"
name="CHelpFlip"
size="18"
color="#000"
/>
</div>
<div class="title">{{ $t('ProductImg.Prompt') }}</div>
<promptInput :content="prompt" ref="promptInputRef" />
</div>
<div class="transferPose" v-show="showMotion">
@@ -389,7 +380,7 @@
<a-spin size="large" />
</div>
<template>
<Prompt v-if="scaleImageList[scaleImageIndex]?.resultType === 'ToProductImage'" v-model:showModal="showPromptAssist" />
<Prompt v-if="scaleImageList[scaleImageIndex]?.resultType === 'ToProductImage'" v-model:showModal="showPromptAssist" isDesignPage />
<PromptEditProduct v-if="scaleImageList[scaleImageIndex]?.resultType === 'Relight'" v-model:showModal="showPromptAssist" />
</template>
<Product
@@ -459,7 +450,7 @@ export default defineComponent({
let userDetail: any = computed(() => {
return store.state.UserHabit.userDetail
})
let { t, locale } = useI18n()
let { t } = useI18n()
const textareaRef = useTemplateRef<HTMLTextAreaElement>('textareaRef')
const videoType = ref(2)
const showMotion = computed(() => videoType.value === 1)
@@ -608,13 +599,13 @@ export default defineComponent({
})
const showPromptAssist = ref(false)
const handleClickAssistBtn = () => {
// const { httpType } = store.state.Workspace.probjects
// const isSingleDesign = httpType === 'SINGLE_DESIGN'
// if (!isSingleDesign) {
// const promptText = t('ProductImg.Series')
// productimg.productimgSearchName = promptText
// return
// }
const { httpType } = store.state.Workspace.probjects
const isSingleDesign = httpType === 'SINGLE_DESIGN'
if (!isSingleDesign) {
const promptText = t('ProductImg.Series')
productimg.productimgSearchName = promptText
return
}
showPromptAssist.value = true
}
@@ -1319,13 +1310,7 @@ export default defineComponent({
return videoType.value === 3 ? false : true
}
})
const handleNavigateHelp = () => {
const url =
locale === 'CHINESE_SIMPLIFIED'
? 'https://aida-user-manual-chinese.super.site/2b08f755cedd80a985cffdf2af80c538'
: 'https://aida-user-manual.super.site/advanced-tool/animated-product-image/to-product-video-prompt-assist '
window.open(url,'_blank')
}
onBeforeUnmount(() => {
clearInterval(prductimgTime)
clearInterval(remPrductimgTime)
@@ -1389,8 +1374,7 @@ export default defineComponent({
handlePlayNewVideo,
isNewVideoPlaying,
showDropdown,
inputPlaceholder,
handleNavigateHelp
inputPlaceholder
}
},
data() {
@@ -1803,14 +1787,10 @@ export default defineComponent({
box-sizing: border-box;
}
.title {
display: flex;
align-items: center;
column-gap: 1rem;
.cursor-icon {
display: flex;
width: auto;
cursor: pointer;
}
font-weight: 500;
color: #000;
font-size: 1.7rem;
margin-bottom: 1.4rem;
}
}
.prompt-container {

View File

@@ -7,7 +7,7 @@
<!-- <div v-show="openType === 'history'" class="function">
<design :key="componentKey" ref="design"></design>
</div> -->
<router-view v-show="
<router-view v-if="
(openType && openType != 'history' && !routeQuery.id) ||
$route.path != '/home'"
@setTask="setTask"
@@ -23,7 +23,7 @@
<!-- <div v-else-if="routeQuery.id" class="function">
<design :key="componentKey" ref="design"></design>
</div> -->
<div v-if="!routeQuery.history" class="function">
<div v-else-if="!routeQuery.history" class="function">
<newPorject ref="newPorject" @newProject=newProject></newPorject>
</div>
<!-- <iframe src="https://kaput-relative-4bb.notion.site/ebd/22a8f755cedd809e98a2c8c6366ee701" width="100%" height="100%" frameborder="0" allowfullscreen /> -->
@@ -55,16 +55,13 @@ export default defineComponent({
const data = reactive({
openType:'',
componentKey:null,
isShowMark:true,
isShowMark:false,
routeQuery:{} as any,
selectObject:computed(()=>store.state.Workspace.probjects) as any,//选择的项目
chatData:null as any,
dataLoad:true as any,
cachedRoutes:computed(()=>store.state.Workspace.cachedRoutes),//
})
onMounted(()=>{
data.isShowMark = false
})
let settingGetHistory:any = inject('settingGetHistory')
const setIsShowMark = (boolean:boolean)=>{
data.isShowMark = boolean

View File

@@ -777,7 +777,6 @@ export default defineComponent({
})
}
const likeSetBtn = (id: any, str: string) => {
console.log(1111)
data.likeList.forEach((item: any, index: any) => {
if (item.id == id && id) {
if (str == 'zoom') {
@@ -815,7 +814,6 @@ export default defineComponent({
let likeFile = (item: any, str: any, index: any) => {
let url
let value = {}
console.log(props.isDesignPage)
if (str == 'like') {
value = {
likeOrDislike: 'like',

View File

@@ -121,7 +121,7 @@ const promptList = computed(() => {
return [t('ProductImg.UploadWithoutModel'), t('ProductImg.UploadWithModel')]
} else {
// 如果是从design来的
if (props.isDesignPage) {
if (isSingleDesign) {
// SINGLE_DESIGN: 两个提示词
// 根据年龄和性别选择对应的提示词
let firstPrompt: string // 不带模特的提示词
@@ -255,8 +255,8 @@ const exampleList = computed(() => {
}
} else {
const { ageGroup, httpType, sex } = store.state.Workspace.probjects
// const isSingleDesign = httpType === 'SINGLE_DESIGN'
// if (!isSingleDesign) return {}
const isSingleDesign = httpType === 'SINGLE_DESIGN'
if (!isSingleDesign) return {}
const isAdult = ageGroup === 'Adult'
const isFemale = sex === 'Female'
if (isAdult) {

View File

@@ -1101,13 +1101,13 @@ export default defineComponent({
const showPromptAssist = ref(false)
const handleClickAssistBtn = () => {
// const { httpType } = store.state.Workspace.probjects
// const isSingleDesign = httpType === 'SINGLE_DESIGN'
// if (props.isDesignPage && !isSingleDesign) {
// const promptText = t('ProductImg.Series')
// productImgData.searchName[props.productimgMenu.value] = promptText
// return
// }
const { httpType } = store.state.Workspace.probjects
const isSingleDesign = httpType === 'SINGLE_DESIGN'
if (props.isDesignPage && !isSingleDesign) {
const promptText = t('ProductImg.Series')
productImgData.searchName[props.productimgMenu.value] = promptText
return
}
showPromptAssist.value = true
}

View File

@@ -51,7 +51,7 @@
<ul
class="product_detail"
:class="[
{ academic: item.type == 'academic' },
{ academic: item.type == 'academic' && !isSelectSuccessively },
{ chinese: isSelectSuccessively }
]"
>
@@ -106,12 +106,12 @@ export default defineComponent({
Yearly: '年度',
monthly: [
{
title: '试用版',
title: '免费版',
img: CChargeIcon,
type: 'personal',
info: '您的AI时尚设计助手',
price: 'HK$0',
detail: '自注册之日起 5 天内 · 50 个积分',
detail: '5天·50积分',
highlight: '',
discounts: '9折优惠',
detailList: [
@@ -185,12 +185,12 @@ export default defineComponent({
],
yearl: [
{
title: '试用版',
title: '免费版',
img: CChargeIcon,
type: 'personal',
info: '您的AI时尚设计助手',
price: 'HK$0',
detail: '自注册之日起 5 天内 · 50 个积分',
detail: '5天·50积分',
highlight: '',
discounts: '9折优惠',
detailList: [
@@ -250,12 +250,12 @@ export default defineComponent({
Yearly: 'Yearly',
monthly: [
{
title: 'Trial',
title: 'Free',
img: CChargeIcon,
type: 'personal',
info: 'Your AI Fashion Design Assistant',
price: 'HK$0',
detail: '5 days from sign-up · 50 credits',
detail: '5 days · 50 credits',
highlight: '',
discounts: '10% off',
detailList: [
@@ -329,12 +329,12 @@ export default defineComponent({
],
yearl: [
{
title: 'Trial',
title: 'Free',
img: CChargeIcon,
type: 'personal',
type: 'free',
info: 'Your AI Fashion Design Assistant',
price: 'HK$0',
detail: '5 days from sign-up · 50 credits',
detail: '5 days · 50 credits',
highlight: '',
discounts: '10% off',
detailList: [

View File

@@ -1543,13 +1543,11 @@ export default {
LoginMethod: '使用以下方式登录:',
Individual: '个人账号',
Academic: '学术账号',
LogonToAiDA: '登录到AiDA 3.1',
LogoOnToAiDA: '登录到AiDA 3.1',
Infomation: '请填写以下信息',
Device: '请使用iPad或电脑登录',
AgreePolicies: '请勾选条款、隐私政策和费用',
PasswordConditions: '您必须满足所有密码条件才能注册',
LoginWithGoogle: '使用谷歌账号登录',
LoginWithWechat: '使用微信登录',
PasswordConditions: '您必须满足所有密码条件才能注册'
},
LoginPersonal: {
Email: '邮箱',

View File

@@ -959,7 +959,7 @@ export default {
MOSTPOPULAR: 'MOST POPULAR',
Monthly: 'Monthly',
Yearly: 'Yearly',
promotionCode: 'Coupon Code',
promotionCode: 'Coupon',
use: 'Apply',
PromoCodeError:
'Please check if the promo code is correct or if the date has expired',
@@ -1591,9 +1591,7 @@ export default {
Infomation: 'Please fill your information below',
Device: 'If you need to design, please log in using an iPad or computer.',
AgreePolicies: 'Please agree to all terms, privacy policy, and fees.',
PasswordConditions: 'You must satisfy ALL password conditions to register.',
LoginWithGoogle: 'Sign in with Google',
LoginWithWechat: 'Sign in with Wechat',
PasswordConditions: 'You must satisfy ALL password conditions to register.'
},
LoginPersonal: {
Email: 'Email',

View File

@@ -290,13 +290,6 @@ const routes: Array<RouteRecordRaw> = [
component: () =>
import("@/component/Administrator/organization/organization.vue"),
},
{
path: "subscriptionPlan",
name: "subscriptionPlan",
meta: { enter: 3 },
component: () =>
import("@/component/Administrator/subscriptionPlan.vue"),
},
//企业版教育管理员页面
{
path: "allUserSE",
@@ -505,17 +498,12 @@ function isTimeRangePassed(timeRange) {
}
router.beforeEach((to: any, from, next) => {
store.commit("set_view_loading", true);
//系统维护时间
const time = '2025-11-21T23:00:00 - 2025-11-22T00:00:00';
if (isTimeRangePassed(time) == 'in_progress') {
// 系统维护
const toName = to.name === 'upgrade';
if(to.query.status == 'admin'){
localStorage.setItem('isAdminVisit', 'true')
}
const isAdminVisit = localStorage.getItem('isAdminVisit') == 'true'
if(upgradeList.indexOf(to.path) > -1 || isAdminVisit){
if(upgradeList.indexOf(to.path) > -1){
next();
}else{
if (toName) {
@@ -525,7 +513,6 @@ router.beforeEach((to: any, from, next) => {
}
}
} else {
localStorage.setItem('isAdminVisit', 'false')
// 机房用户
let herfData = window.location.search.substring(1);
@@ -553,7 +540,5 @@ router.beforeEach((to: any, from, next) => {
// if(systemUser == 0){//游客用户只能进入这两个页面
});
router.afterEach((to, from) => {
store.commit("set_view_loading", false);
});
export default router;

View File

@@ -13,18 +13,10 @@ export interface RootState{
export default createStore<RootState>({
state: {
loading: false,
view_loading: false,
},
getters: {
},
mutations: {
set_loading(state, v){
state.loading = v;
},
set_view_loading(state, v){
state.view_loading = v;
},
},
actions: {
},

View File

@@ -177,12 +177,6 @@ const all = (t)=>{
route:'/administrator/organization',
key:'sub13',
isShow:true,
},{
name:'Subscription Plan',
icon:'usetime',
route:'/administrator/subscriptionPlan',
key:'sub14',
isShow:true,
}]
}
const schoolOrEnterprise = (t) =>{

View File

@@ -325,11 +325,6 @@ export const Https = {
deletePromCode:`/api/stripe/deletePromCode`,//删除优惠券
addOrganization:`/api/inquiry/addOrganization`,//添加企业版或者教育版
queryOrganization:`/api/inquiry/queryOrganization`,//查询企业版或者教育版
createSubscribePlan:'/api/subscription_plan/createPlan', // 创建订阅计划
deleteSubscribePlan: '/api/subscription_plan/deletePlan', // 删除订阅计划
updateSubscribePlan: '/api/subscription_plan/updatePlan', // 修改订阅计划
searchAllSubscribePlan: '/api/subscription_plan/searchByPage', // 查询所有订阅计划
switchSubscribePlan:'/api/subscription_plan/switchSubscriptionPlan', // 切换订阅计划
//云生成

View File

@@ -394,23 +394,23 @@
<span class="select_item_des">{{ $t('Header.Tutorial') }}</span>
</div>
<div class="select_item logo">
<a href="https://www.tiktok.com/@aida_codecreate" target="_blank" >
<img src="@/assets/images/socialMediaLogo/tikTokIcon.svg" alt="">
<a href="https://www.tiktok.com" target="_blank" >
<img src="@/assets/images/socialMediaLogo/tikTokIcon.png" alt="">
</a>
<a href="https://www.facebook.com/CodeCreateAI" target="_blank" >
<img src="@/assets/images/socialMediaLogo/faceBookIcon.svg" alt="">
<a href="https://www.instagram.com" target="_blank" >
<img src="@/assets/images/socialMediaLogo/instagramIcon.png" alt="">
</a>
<a href="https://www.youtube.com/@AiDA-3.1" target="_blank" >
<img src="@/assets/images/socialMediaLogo/socialIcons.svg" alt="">
<a href="https://www.youtube.com" target="_blank" >
<img src="@/assets/images/socialMediaLogo/youTubeIcon.png" alt="">
</a>
<a href="https://www.linkedin.com/company/code-create-limited" target="_blank" >
<img src="@/assets/images/socialMediaLogo/linkedinIcon.svg" alt="">
<a href="https://www.xiaohongshu.com" target="_blank" >
<img src="@/assets/images/socialMediaLogo/xiaoHongShuIcon.png" alt="">
</a>
<a href="https://xhslink.com/m/5Ony2FapizV" target="_blank" >
<img src="@/assets/images/socialMediaLogo/xiaoHongShuIcon.svg" alt="">
<a href="https://www.zhihu.com" target="_blank" >
<img src="@/assets/images/socialMediaLogo/zhiHuIcon.png" alt="">
</a>
<a href="https://space.bilibili.com/3546717609789876?spm_id_from=333.788.upinfo.head.click" target="_blank" >
<img src="@/assets/images/socialMediaLogo/biliBliIcon.svg" alt="">
<a href="https://www.bilibili.com/" target="_blank" >
<img src="@/assets/images/socialMediaLogo/biliBliIcon.png" alt="">
</a>
</div>
@@ -427,12 +427,11 @@
<div class="userSystem" v-show="pastDuePage">
{{ $t('Header.pastDue') }}
</div>
<div class="router" v-if="!loading">
<div class="router" v-if="!getLangIsShowMark">
<home
ref="home"
@setNewProject="() => (leftShow = true)"
@setTask="setTask"
:key="userDetail.language"
></home>
</div>
</div>
@@ -443,10 +442,10 @@
<UpgradePlan ref="UpgradePlan"></UpgradePlan>
<TaskPage ref="TaskPage"></TaskPage>
<!-- <div class="mark_loading" v-show="loading">
<div class="mark_loading" v-show="getLangIsShowMark">
<a-spin size="large" />
</div> -->
<!-- <RobotAssist v-if="!loading"></RobotAssist> -->
</div>
<!-- <RobotAssist v-if="!getLangIsShowMark"></RobotAssist> -->
<scaleVideo ref="scaleVideo"></scaleVideo>
<!-- 进行续订 -->
<renew ref="renew"></renew>
@@ -657,7 +656,7 @@ export default defineComponent({
})
let activeCredits = ref(false)
let loading = computed(() => (store.state.loading))
let getLangIsShowMark = ref(true)
let messageNum = computed(() => {
return store.state.UserHabit.messageSystem.messageNum
})
@@ -1071,7 +1070,7 @@ export default defineComponent({
isMurmur,
credits,
activeCredits,
loading,
getLangIsShowMark,
messageNum,
messageType,
...toRefs(stateList),
@@ -1129,11 +1128,11 @@ export default defineComponent({
this.store
.dispatch('getLangType')
.then(() => {
this.store.commit('set_loading', false)
this.getLangIsShowMark = false
resolve()
})
.catch(() => {
this.store.commit('set_loading', false)
this.getLangIsShowMark = false
reject()
})
})
@@ -1335,7 +1334,7 @@ export default defineComponent({
})
},
setLang(v) {
this.store.commit('set_loading', true)
this.getLangIsShowMark = true
Https.axiosGet(Https.httpUrls.changeUserLanguage, { params: { language: v } })
.then(rv => {
if (rv) {
@@ -1352,11 +1351,11 @@ export default defineComponent({
window.location.reload()
// window.location.href = '/home';
}
this.store.commit('set_loading', false)
this.getLangIsShowMark = false
}
})
.catch(() => {
this.store.commit('set_loading', false)
this.getLangIsShowMark = false
})
},
@@ -2039,15 +2038,16 @@ export default defineComponent({
}
.logo{
padding: 1rem 0.5rem;
gap: 1.8rem;
gap: 1rem;
cursor: auto;
justify-content: center;
> a{
width: auto;
height: 2.4rem;
width: 2.5rem;
height: 2.5rem;
border-radius: .5rem;
overflow: hidden;
display: flex;
> img{
width: 100%;
height: 100%;
}
}

View File

@@ -175,7 +175,7 @@ export default defineComponent({
if (record.text == 1) {
str = useI18n().t('newScaleImage.Original')
} else {
str = `@${record.record.originalAccountName}/${record.record.originalPortfolioName}`
str = `@${record.record.userLikeGroupVO.originalAccountName}/${record.record.userLikeGroupVO.originalPortfolioName}`
}
// let time = formatTime(record.text / 1000, 'YYYY-MM-DD hh:mm:ss')
return str

View File

@@ -43,12 +43,15 @@
<span>{{ t('Login.LogonToAiDA') }}</span>
</div>
<div class="info" v-show="!loginType">{{ t('Login.Infomation') }}</div>
<personal ref="personal" v-if="loginType == 'personal'"></personal>
<personal ref="personal" v-if="loginType == 'personal'" v-model:isMask="isMask"></personal>
<school ref="school" v-if="loginType == 'school'"></school>
<enterprise ref="enterprise" v-if="loginType == 'enterprise'"></enterprise>
</div>
</div>
<div class="mark_loading" v-show="isMask">
<a-spin size="large" />
</div>
</div>
</div>
</template>
@@ -100,6 +103,7 @@ export default defineComponent({
const loginData = reactive({
loginType: "",
isMask: false,
});
const dataDom = reactive({
personal: null as any,