+
+
+
{{ t('admin.orders.basicInfo') }}
+
+
+ {{ selectedOrder.id }}
+
+
+ {{ selectedOrder.order_no }}
+
+
+ {{ (selectedOrder?.order_info?.shipping?.firstName || '') + (selectedOrder?.order_info?.shipping?.lastName || '') }}
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
@@ -286,26 +310,56 @@
>
+
+ {{ selectedOrder.id }}
+
+
+ {{ selectedOrder.order_no }}
+
+
+ {{ (selectedOrder?.order_info?.shipping?.firstName || '') + (selectedOrder?.order_info?.shipping?.lastName || '') }}
+
{{ selectedOrder.trackingNumber || 'SF1234567890' }}
{{ selectedOrder.carrier || '顺丰速运' }}
+
+ {{ selectedOrder.logisticsCompanyCode || 'SF' }}
+
+
+
+ {{ selectedOrder.logisticsStatusText || '未知' }}
+
+
+
+ {{ selectedOrder.currentLocation || '未知' }}
+
{{ t('admin.orders.logisticsTimeline') }}
-
-
- {{ activity.content }}
-
-
+
+
+
+
+
{{ activity.content }}
+
{{ activity.location }}
+
+
+
+
+ {{ t('admin.orders.noLogisticsData') }}
+
+
{{ t('common.close') }}
@@ -417,7 +471,7 @@
import { ref, computed, onMounted, reactive,watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
-import { orderStatus } from '@deotaland/utils'
+import { orderStatus, LogistIcsService } from '@deotaland/utils'
import {
Download,
ShoppingCart,
@@ -428,6 +482,9 @@ import {
} from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {AdminOrders} from './AdminOrders'
+
+// 物流服务实例
+const logisticsService = new LogistIcsService()
const adminOrders = new AdminOrders()
// 组合式函数
const { t } = useI18n()
@@ -477,34 +534,14 @@ const handleDisassemble = (order) => {
}
// 发货表单
const shippingForm = reactive({
- trackingNumber: '',
- carrier: '',
- note: ''
+ trackingNo: '',
+ logisticsCompany: null,
+ logisticsCompanyCode: '',
+ remark: ''
})
// 物流活动时间线
-const logisticsActivities = ref([
- {
- content: '您的订单已发货',
- timestamp: '2023-12-01 10:00:00',
- type: 'primary'
- },
- {
- content: '您的订单已到达【北京转运中心】',
- timestamp: '2023-12-01 14:30:00',
- type: 'success'
- },
- {
- content: '您的订单正在派送中',
- timestamp: '2023-12-02 09:00:00',
- type: 'warning'
- },
- {
- content: '您的订单已签收',
- timestamp: '2023-12-02 16:30:00',
- type: 'success'
- }
-])
+const logisticsActivities = ref([])
// 模拟订单数据
const ordersList = ref()
@@ -556,7 +593,7 @@ const handleExportOrders = () => {
}
const refresh = () => {
- console.log('Refresh data')
+ getList()
ElMessage.success('Data refreshed successfully')
}
@@ -608,31 +645,103 @@ const handleShipOrder = (row) => {
// 查看物流
const handleViewLogistics = (row) => {
selectedOrder.value = row
- logisticsDialogVisible.value = true
+
+ // 清空之前的物流数据
+ logisticsActivities.value = []
+
+ // 调用真实物流接口获取数据
+ logisticsService.getLogisticsByOrderId({ orderId: row.id }).then(res => {
+ if (res.code === 0 && res.data) {
+ // 从接口返回的数据中提取物流信息
+ const logisticsData = res.data
+
+ // 保存物流基本信息到selectedOrder对象,用于在对话框中显示
+ selectedOrder.value.trackingNumber = logisticsData.trackingNo
+ selectedOrder.value.carrier = logisticsData.logisticsCompany
+ selectedOrder.value.logisticsStatusText = logisticsData.logisticsStatusText
+ selectedOrder.value.logisticsCompanyCode = logisticsData.logisticsCompanyCode
+ selectedOrder.value.logisticsStatus = logisticsData.logisticsStatus
+ selectedOrder.value.currentLocation = logisticsData.currentLocation
+
+ // 转换物流轨迹数据为时间线格式
+ if (logisticsData.traces && Array.isArray(logisticsData.traces)) {
+ // 将traces转换为符合现有时间线组件要求的格式
+ logisticsActivities.value = logisticsData.traces.map(trace => ({
+ timestamp: trace.time,
+ content: trace.description,
+ location: trace.location,
+ action: trace.action
+ }))
+ } else {
+ // 接口调用成功但没有轨迹数据,清空物流活动
+ logisticsActivities.value = []
+ }
+ } else {
+ // 接口调用失败,清空物流活动
+ logisticsActivities.value = []
+ ElMessage.warning('获取物流信息失败')
+ }
+
+ // 显示物流对话框
+ logisticsDialogVisible.value = true
+ }).catch(err => {
+ console.error('获取物流信息失败:', err)
+ ElMessage.error('获取物流信息失败')
+ logisticsActivities.value = []
+ logisticsDialogVisible.value = true
+ })
}
// 确认发货
const confirmShipOrder = () => {
- if (!shippingForm.trackingNumber || !shippingForm.carrier) {
+ // 验证必填字段
+ if (!shippingForm.trackingNo || !shippingForm.logisticsCompany || !shippingForm.logisticsCompanyCode) {
ElMessage.warning('请填写必要的发货信息')
return
}
- // 更新订单状态
- const orderIndex = ordersList.value.findIndex(order => order.id === selectedOrder.value.id)
- if (orderIndex !== -1) {
- ordersList.value[orderIndex].status = 'shipped'
- ordersList.value[orderIndex].trackingNumber = shippingForm.trackingNumber
- ordersList.value[orderIndex].carrier = shippingForm.carrier
+ // 准备发货数据
+ const shipData = {
+ orderId: selectedOrder.value.id,
+ orderNo: selectedOrder.value.order_no,
+ trackingNo: shippingForm.trackingNo,
+ logisticsCompanyCode: shippingForm.logisticsCompanyCode,
+ logisticsCompany: shippingForm.logisticsCompany,
+ customerName: (selectedOrder.value?.order_info?.shipping?.firstName || '') + (selectedOrder.value?.order_info?.shipping?.lastName || ''),
+ remark: shippingForm.remark
}
- ElMessage.success('发货成功')
- shippingDialogVisible.value = false
-
- // 重置表单
- shippingForm.trackingNumber = ''
- shippingForm.carrier = ''
- shippingForm.note = ''
+ // 调用发货API
+ logisticsService.ship(shipData).then(res => {
+ if (res.code === 0) {
+ // 更新订单状态
+ // const orderIndex = ordersList.value.findIndex(order => order.id === selectedOrder.value.id)
+ // if (orderIndex !== -1) {
+ // ordersList.value[orderIndex].status = 'shipped'
+ // ordersList.value[orderIndex].trackingNumber = shippingForm.trackingNo
+ // ordersList.value[orderIndex].carrier = shippingForm.logisticsCompany
+ // }
+ ElMessage.success('发货成功')
+ shippingDialogVisible.value = false;
+ init();
+ // shippingDialogVisible.value = false
+ // // 重置表单
+ // resetShippingForm()
+ } else {
+ ElMessage.error(res.msg || '发货失败,请重试')
+ }
+ }).catch(err => {
+ console.error('发货失败:', err)
+ ElMessage.error('发货失败,请重试')
+ })
+}
+
+// 重置发货表单
+const resetShippingForm = () => {
+ shippingForm.trackingNo = ''
+ shippingForm.logisticsCompany = null
+ shippingForm.logisticsCompanyCode = ''
+ shippingForm.remark = ''
}
// 图片预览
@@ -1012,4 +1121,86 @@ onMounted(() => {
.preview-image:hover {
transform: scale(1.02);
}
+
+/* 订单列表商品图片样式 */
+.order-item-image {
+ width: 40px;
+ height: 40px;
+ object-fit: cover;
+ border-radius: 4px;
+ cursor: pointer;
+ transition: transform 0.2s ease;
+}
+
+.order-item-image:hover {
+ transform: scale(1.1);
+}
+
+/* 订单信息区域样式 */
+.order-info-section {
+ margin-bottom: 20px;
+ padding: 16px;
+ background-color: #f5f7fa;
+ border-radius: 8px;
+}
+
+.order-info-section h4 {
+ margin: 0 0 16px 0;
+ font-size: 16px;
+ font-weight: 600;
+ color: #1f2937;
+}
+
+/* 物流时间线容器 */
+.logistics-timeline-container {
+ max-height: 400px;
+ overflow-y: auto;
+ padding-right: 8px;
+ margin-top: 16px;
+ border-radius: 8px;
+ /* 添加滚动条样式 */
+ scrollbar-width: thin;
+ scrollbar-color: #d1d5db #f3f4f6;
+}
+
+/* 自定义滚动条 */
+.logistics-timeline-container::-webkit-scrollbar {
+ width: 6px;
+}
+
+.logistics-timeline-container::-webkit-scrollbar-track {
+ background: #f3f4f6;
+ border-radius: 3px;
+}
+
+.logistics-timeline-container::-webkit-scrollbar-thumb {
+ background-color: #d1d5db;
+ border-radius: 3px;
+ border: 2px solid #f3f4f6;
+}
+
+.logistics-timeline-container::-webkit-scrollbar-thumb:hover {
+ background-color: #9ca3af;
+}
+
+/* 物流时间线样式 */
+.logistics-item {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+ margin-bottom: 16px;
+}
+
+.logistics-content {
+ font-size: 14px;
+ color: #333;
+ line-height: 1.5;
+}
+
+.logistics-location {
+ font-size: 12px;
+ color: #666;
+ margin-top: 4px;
+ font-style: italic;
+}
\ No newline at end of file
diff --git a/apps/FrontendDesigner/src/views/admin/AdminUsers/AdminUserInvites.vue b/apps/FrontendDesigner/src/views/admin/AdminUsers/AdminUserInvites.vue
new file mode 100644
index 0000000..aa7e20b
--- /dev/null
+++ b/apps/FrontendDesigner/src/views/admin/AdminUsers/AdminUserInvites.vue
@@ -0,0 +1,205 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ formatDateTime(row.createdAt) }}
+
+
+
+
+
+ {{ getStatusLabel(row.status) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/FrontendDesigner/src/views/admin/AdminUsers.vue b/apps/FrontendDesigner/src/views/admin/AdminUsers/AdminUsers.vue
similarity index 65%
rename from apps/FrontendDesigner/src/views/admin/AdminUsers.vue
rename to apps/FrontendDesigner/src/views/admin/AdminUsers/AdminUsers.vue
index 67da6ac..a04ea6b 100644
--- a/apps/FrontendDesigner/src/views/admin/AdminUsers.vue
+++ b/apps/FrontendDesigner/src/views/admin/AdminUsers/AdminUsers.vue
@@ -1,7 +1,7 @@
-
+
@@ -45,11 +45,11 @@
-
-
+
+
-
-
+
+
@@ -59,6 +59,8 @@
:placeholder="t('admin.users.search')"
:prefix-icon="Search"
clearable
+ @keyup.enter="handleSearch"
+ @clear="handleSearch"
/>
@@ -75,29 +77,15 @@
-
-
-
-
- {{ row.username.charAt(0).toUpperCase() }}
-
-
-
-
-
+
-
@@ -105,17 +93,23 @@
-
+
- {{ formatDate(row.registerDate) }}
+ {{ formatDateTime(row.lastActive) }}
-
+
+
- {{ formatDateTime(row.lastLogin) }}
+ {{ row.inviterNickname || '-' }}
-
+
+
+ {{ formatDateTime(row.createdAt) }}
+
+
+
@@ -124,25 +118,29 @@
{{ t('admin.users.edit') }}
-
- {{ t('admin.users.resetPassword') }}
-
- {{ t('admin.users.ban') }}
-
-
- {{ t('admin.users.unban') }}
-
+ v-if="row.status === 'active'"
+ size="small"
+ type="danger"
+ @click="handleBan(row)"
+ >
+ {{ t('admin.users.ban') }}
+
+
+ {{ t('admin.users.unban') }}
+
+
+ 邀请列表
+
@@ -174,48 +172,39 @@
-
- {{ selectedUser?.username?.charAt(0).toUpperCase() }}
+
+ {{ selectedUser?.nickname?.charAt(0).toUpperCase() }}
-
- {{ selectedUser?.username }}
+
+ {{ selectedUser?.id || '-' }}
-
- {{ selectedUser?.realName || '-' }}
+
+ {{ selectedUser?.nickname || '-' }}
- {{ selectedUser?.email }}
+ {{ selectedUser?.email || '-' }}
- {{ selectedUser?.phone }}
-
-
-
- {{ selectedUser.creatorLevel }}
-
- -
-
-
- {{ selectedUser?.worksCount || 0 }}
-
-
- {{ selectedUser ? t(`admin.users.roleOptions.${selectedUser.role}`) : '' }}
+ {{ selectedUser?.phone || '-' }}
- {{ selectedUser ? t(`admin.users.statusOptions.${selectedUser.status}`) : '' }}
+ {{ selectedUser ? t(`admin.users.statusOptions.${selectedUser.status}`) : '-' }}
-
- {{ selectedUser?.loginCount }}
+
+ {{ selectedUser?.inviteCode || '-' }}
+
+
+ {{ selectedUser?.inviterNickname || '-' }}
- {{ formatDate(selectedUser?.registerDate) }}
+ {{ formatDateTime(selectedUser?.createdAt) }}
- {{ formatDateTime(selectedUser?.lastLogin) }}
+ {{ formatDateTime(selectedUser?.lastActive) }}
-
- {{ selectedUser?.bio || '-' }}
+
+ {{ formatDateTime(selectedUser?.updatedAt) }}
@@ -228,48 +217,8 @@
width="600px"
>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -302,7 +251,8 @@
diff --git a/apps/FrontendDesigner/src/views/admin/AdminUsers/index.js b/apps/FrontendDesigner/src/views/admin/AdminUsers/index.js
new file mode 100644
index 0000000..d90e609
--- /dev/null
+++ b/apps/FrontendDesigner/src/views/admin/AdminUsers/index.js
@@ -0,0 +1,70 @@
+import { adminApi,requestUtils} from '@deotaland/utils';
+
+export class AdminOrders {
+ constructor() {
+ }
+ // 获取用户列表
+ async getUsersList(data) {
+ let params = {
+ nickname: data.nickname || '',
+ email: data.email || '',
+ status: data.status || '',
+ pageSize: data.pageSize || 10,
+ pageNum: data.pageNum || 1,
+ orderByColumn: data.orderByColumn || '',
+ isAsc: data.isAsc || 'asc'
+ }
+ return requestUtils.common(adminApi.default.getUsersList, params);
+ }
+ // 获取用户详情
+ async getUserDetail(data) {
+ let params = {
+ id: data.id || ''
+ }
+ const requestUrl = {
+ method: adminApi.default.getUserDetail.method,
+ url: adminApi.default.getUserDetail.url.replace('USERID', params.id)
+ }
+ return requestUtils.common(requestUrl, params);
+ }
+ // 更新用户状态
+ async updateUserStatus(data) {
+ let params = {
+ id : data.id || '',
+ status : data.status || ''
+ }
+ const requestUrl = {
+ method: adminApi.default.updateUserStatus.method,
+ url: (adminApi.default.updateUserStatus.url.replace('USERID', params.id))+'?'+'id='+data.id+'&status='+data.status
+ }
+ return requestUtils.common(requestUrl, params);
+ }
+ //更新用户名称
+ async updateUserName(data) {
+ let params = {
+ id: data.id || '',
+ nickname: data.nickname || ''
+ }
+ const requestUrl = {
+ method: adminApi.default.updateUserName.method,
+ url: adminApi.default.updateUserName.url.replace('USERID', params.id)
+ }
+ return requestUtils.common(requestUrl, params);
+ }
+ //查询指定用户邀请的人列表
+ async getUsersInvites(data) {
+ let params = {
+ id: data.id || '',
+ pageSize: data.pageSize || 10,
+ pageNum: data.pageNum || 1,
+ orderByColumn: data.orderByColumn || '',
+ isAsc: data.isAsc || 'asc'
+ }
+ const requestUrl = {
+ method: adminApi.default.getUsersinvites.method,
+ url: adminApi.default.getUsersinvites.url.replace('USERID', params.id)
+ }
+ return requestUtils.common(requestUrl, params);
+ }
+
+}
\ No newline at end of file
diff --git a/apps/FrontendDesigner/vite.config.js b/apps/FrontendDesigner/vite.config.js
index 04fecfa..2b6c43e 100644
--- a/apps/FrontendDesigner/vite.config.js
+++ b/apps/FrontendDesigner/vite.config.js
@@ -34,8 +34,8 @@ export default defineConfig({
// 配置代理解决CORS问题
proxy: {
'/api': {
- // target: 'https://api.deotaland.ai',
- target: 'http://192.168.0.174:9000',
+ target: 'https://api.deotaland.ai',
+ // target: 'http://192.168.0.174:9000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
diff --git a/apps/frontend/index.html b/apps/frontend/index.html
index 671666a..eb2eb5f 100644
--- a/apps/frontend/index.html
+++ b/apps/frontend/index.html
@@ -2,7 +2,7 @@
-
+
diff --git a/apps/frontend/package.json b/apps/frontend/package.json
index c6175aa..c6c84ba 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",
- "@splinetool/runtime": "^1.12.6",
"@stripe/stripe-js": "^4.8.0",
"@twind/core": "^1.1.3",
"@twind/preset-autoprefix": "^1.0.7",
diff --git a/apps/frontend/public/vite.svg b/apps/frontend/public/vite.svg
deleted file mode 100644
index 457215d..0000000
--- a/apps/frontend/public/vite.svg
+++ /dev/null
@@ -1,635 +0,0 @@
-
-
diff --git a/apps/frontend/src/App.vue b/apps/frontend/src/App.vue
index 5c57699..afec1c4 100644
--- a/apps/frontend/src/App.vue
+++ b/apps/frontend/src/App.vue
@@ -4,6 +4,7 @@ import { useRouter, useRoute } from 'vue-router'
import MainLayout from '@/components/layout/MainLayout.vue'
import AppHeader from '@/components/layout/AppHeader.vue'
import AppSidebar from '@/components/layout/AppSidebar.vue'
+import LoadingCom from './components/LoadingCom/index.vue';
const route = useRoute()
// 判断当前是否为登录页面
const isLoginPage = computed(() => route.path === '/login')
@@ -58,15 +59,18 @@ onMounted(() => {
'fullscreen-mode': isFullScreenPage,
'homepage-mode': isHomePage
}">
-
+
+
-
+
+
-
+
+
@@ -96,76 +100,7 @@ onMounted(() => {
border-radius: 0 !important;
}
-/* 侧边栏过渡动画蒙层 */
-.sidebar-overlay {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- /* background: rgba(111, 75, 197, 0.1); */
- /* background: red; */
- backdrop-filter: blur(8px);
- -webkit-backdrop-filter: blur(8px);
- z-index: 9999;
- opacity: 0;
- visibility: hidden;
- transition: all 0.6s cubic-bezier(0.4, 0, 0.2, 1);
- border-radius: 12px;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-/* 蒙层激活状态 */
-.sidebar-overlay-active {
- opacity: 1;
- visibility: visible;
-}
-
-/* 转圈加载动画 */
-.sidebar-overlay::before {
- content: '';
- width: 50px;
- height: 50px;
- border: 4px solid rgba(113, 77, 199, 0.3);
- border-top: 4px solid #714DC7;
- border-radius: 50%;
- animation: spin 1s linear infinite;
- box-shadow: 0 0 20px rgba(113, 77, 199, 0.5);
-}
-
-.sidebar-overlay::after {
- content: '';
- position: absolute;
- width: 70px;
- height: 70px;
- border: 2px solid rgba(113, 77, 199, 0.1);
- border-bottom: 2px solid rgba(113, 77, 199, 0.3);
- border-radius: 50%;
- animation: spin 1.5s linear infinite reverse;
-}
-
-@keyframes spin {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
-}
-
-/* 暗色主题下的蒙层效果 */
-html.dark .sidebar-overlay {
- background: rgba(31, 41, 55, 0.85);
-}
-
-html.dark .sidebar-overlay::before {
- border: 4px solid rgba(255, 255, 255, 0.2);
- border-top: 4px solid #A78BFA;
- box-shadow: 0 0 20px rgba(167, 139, 250, 0.5);
-}
-
-html.dark .sidebar-overlay::after {
- border: 2px solid rgba(167, 139, 250, 0.1);
- border-bottom: 2px solid rgba(167, 139, 250, 0.4);
-}
\ No newline at end of file
diff --git a/apps/frontend/src/components/LogisticsTimeline.vue b/apps/frontend/src/components/LogisticsTimeline.vue
index 17f244c..f4004c8 100644
--- a/apps/frontend/src/components/LogisticsTimeline.vue
+++ b/apps/frontend/src/components/LogisticsTimeline.vue
@@ -123,7 +123,7 @@ const EVENT_TYPES = {
SHIPPED: 'shipped',
IN_TRANSIT: 'in_transit',
OUT_FOR_DELIVERY: 'out_for_delivery',
- DELIVERED: 'delivered',
+ delivered: 'Shipped',
EXCEPTION: 'exception'
}
diff --git a/apps/frontend/src/components/iPandCardLeft/index copy.vue b/apps/frontend/src/components/iPandCardLeft/index copy.vue
new file mode 100644
index 0000000..a8376fc
--- /dev/null
+++ b/apps/frontend/src/components/iPandCardLeft/index copy.vue
@@ -0,0 +1,2457 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/frontend/src/components/iPandCardLeft/index.vue b/apps/frontend/src/components/iPandCardLeft/index.vue
index a8376fc..1b7192e 100644
--- a/apps/frontend/src/components/iPandCardLeft/index.vue
+++ b/apps/frontend/src/components/iPandCardLeft/index.vue
@@ -1,24 +1,26 @@