Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions .idea/aws.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions .idea/web_b2b.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# 基于Python开发的B2B企业英文网站


> 基于React+django开发的b2b企业网站,适用场景包括外贸独立站、企业官网、产品展示网站等场景。自2025年9月9日起本项目不再维护。
> 基于React+django开发的b2b企业网站(大部分代码使用AI编写),适用场景包括外贸独立站、企业官网、产品展示网站等场景。自2025年9月9日起本项目不再维护。


## 在线演示
Expand Down Expand Up @@ -79,11 +79,15 @@ python manage.py runserver
```
npm install
```
(2) 构建项目
(2) 修改.env配置

修改.env文件中的域名,改成你自己的域名。

(3) 构建项目
```
npm run build
```
(3) 运行
(4) 运行
```
npm run start
```
Expand Down
30 changes: 30 additions & 0 deletions server/info.log
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,33 @@ Forbidden: /myapp/admin/overview/count
"GET /myapp/index/home/section HTTP/1.1" 200 4959
"GET /myapp/index/thing/section?page=1&pageSize=9&searchQuery= HTTP/1.1" 200 3521
"GET /myapp/index/thing/section?page=1&pageSize=9 HTTP/1.1" 200 3521
Watching for file changes with StatReloader
Watching for file changes with StatReloader
Watching for file changes with StatReloader
D:\git_workspace\web_b2b\server\server\settings.py changed, reloading.
Watching for file changes with StatReloader
"GET /myapp/index/common/section HTTP/1.1" 200 4265
"GET /myapp/index/home/section HTTP/1.1" 200 4959
"GET /myapp/index/home/section HTTP/1.1" 200 4959
"GET /myapp/index/home/section HTTP/1.1" 200 4959
"GET /myapp/index/common/section HTTP/1.1" 200 4265
"GET /myapp/index/home/section HTTP/1.1" 200 4959
"GET /myapp/index/common/section HTTP/1.1" 200 4265
"GET /myapp/index/home/section HTTP/1.1" 200 4959
"GET /myapp/index/home/section HTTP/1.1" 200 4959
"GET /myapp/index/home/section HTTP/1.1" 200 4959
"GET /myapp/index/common/section HTTP/1.1" 200 4265
"GET /myapp/index/home/section HTTP/1.1" 200 4959
"GET /myapp/index/home/section HTTP/1.1" 200 4959
"GET /myapp/index/common/section HTTP/1.1" 200 4265
"GET /myapp/index/home/section HTTP/1.1" 200 4959
"GET /myapp/index/common/section HTTP/1.1" 200 4265
"GET /myapp/index/home/section HTTP/1.1" 200 4959
"GET /myapp/index/common/section HTTP/1.1" 200 4265
"GET /myapp/index/common/section HTTP/1.1" 200 4265
"GET /myapp/index/home/section HTTP/1.1" 200 4959
"GET /myapp/index/home/section HTTP/1.1" 200 4959
"GET /myapp/index/common/section HTTP/1.1" 200 4265
"GET /myapp/index/thing/section?page=1&pageSize=9 HTTP/1.1" 200 3521
"GET /myapp/index/thing/section?page=1&pageSize=12&searchQuery= HTTP/1.1" 200 3937
"GET /myapp/index/about/section HTTP/1.1" 200 4216
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
44 changes: 44 additions & 0 deletions server/myapp/views/admin/basicTdk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Create your views here.

from rest_framework.decorators import api_view, authentication_classes

from myapp.auth.authentication import AdminTokenAuthtication
from myapp.handler import APIResponse
from myapp.models import BasicTdk
from myapp.permission.permission import isDemoAdminUser, check_if_demo
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isDemoAdminUser is imported but never used in this module. Please remove the unused import to keep the file clean.

Suggested change
from myapp.permission.permission import isDemoAdminUser, check_if_demo
from myapp.permission.permission import check_if_demo

Copilot uses AI. Check for mistakes.
from myapp.serializers import BasicTdkSerializer
from myapp.utils import after_call, clear_cache


@api_view(['GET'])
@authentication_classes([AdminTokenAuthtication])
def list_api(request):
if request.method == 'GET':
basicTdk = BasicTdk.get_solo()

serializer = BasicTdkSerializer(basicTdk, many=False)
return APIResponse(code=0, msg='查询成功', data=serializer.data)




@api_view(['POST'])
@authentication_classes([AdminTokenAuthtication])
@check_if_demo
@after_call(clear_cache)
def update(request):

try:
basicTdk = BasicTdk.get_solo()
serializer = BasicTdkSerializer(basicTdk, data=request.data)
if serializer.is_valid():
serializer.save()
return APIResponse(code=0, msg='更新成功', data=serializer.data)
else:
print(serializer.errors)
except BasicTdk.DoesNotExist:
return APIResponse(code=1, msg='对象不存在')

return APIResponse(code=1, msg='更新失败')


90 changes: 90 additions & 0 deletions server/myapp/views/admin/case.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Create your views here.

from rest_framework.decorators import api_view, authentication_classes
from rest_framework.pagination import PageNumberPagination

from myapp.auth.authentication import AdminTokenAuthtication
from myapp.handler import APIResponse
from myapp.models import Case
from myapp.permission.permission import isDemoAdminUser, check_if_demo
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isDemoAdminUser is imported but never used in this module. Please remove the unused import to keep the file clean.

Suggested change
from myapp.permission.permission import isDemoAdminUser, check_if_demo
from myapp.permission.permission import check_if_demo

Copilot uses AI. Check for mistakes.
from myapp.serializers import CaseSerializer
from myapp.utils import after_call, clear_cache


class MyPageNumberPagination(PageNumberPagination):
page_size = 10 # 每页的默认项
page_size_query_param = 'pageSize' # 允许通过 URL 参数设置每页的大小
max_page_size = 100 # 最大页尺寸


@api_view(['GET'])
@authentication_classes([AdminTokenAuthtication])
def list_api(request):
if request.method == 'GET':
keyword = request.GET.get("keyword", '')
case = Case.objects.filter(title__contains=keyword).order_by('-create_time')

# 分页
paginator = MyPageNumberPagination()
paginated_case = paginator.paginate_queryset(case, request)
total = case.count()

serializer = CaseSerializer(paginated_case, many=True)
return APIResponse(code=0, msg='查询成功', data=serializer.data, total=total)


@api_view(['POST'])
@authentication_classes([AdminTokenAuthtication])
@check_if_demo
@after_call(clear_cache)
def create(request):

if not request.data.get('title', None):
return APIResponse(code=1, msg='标题不能为空')

data = request.data.copy()
serializer = CaseSerializer(data=data)
if serializer.is_valid():
serializer.save()
return APIResponse(code=0, msg='创建成功', data=serializer.data)
else:
print(serializer.errors)

return APIResponse(code=1, msg='创建失败')


@api_view(['POST'])
@authentication_classes([AdminTokenAuthtication])
@check_if_demo
@after_call(clear_cache)
def update(request):

try:
pk = request.data['id']
case = Case.objects.get(pk=pk)
except Case.DoesNotExist:
return APIResponse(code=1, msg='对象不存在')

data = request.data.copy()
serializer = CaseSerializer(case, data=data)
if serializer.is_valid():
serializer.save()
return APIResponse(code=0, msg='更新成功', data=serializer.data)
else:
print(serializer.errors)
return APIResponse(code=1, msg='更新失败')


@api_view(['POST'])
@check_if_demo
@authentication_classes([AdminTokenAuthtication])
Comment on lines +79 to +80
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decorator order is inconsistent with other admin views: @authentication_classes(...) typically comes before @check_if_demo so auth-related request context is consistently applied. Please reorder decorators to match the established pattern for readability/consistency.

Suggested change
@check_if_demo
@authentication_classes([AdminTokenAuthtication])
@authentication_classes([AdminTokenAuthtication])
@check_if_demo

Copilot uses AI. Check for mistakes.
def delete(request):

try:
ids = request.data['ids']
ids_arr = ids.split(',')
Case.objects.filter(id__in=ids_arr).delete()
except Case.DoesNotExist:
return APIResponse(code=1, msg='对象不存在')

Comment on lines +83 to +89
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The try/except Case.DoesNotExist around Case.objects.filter(...).delete() will never catch DoesNotExist because filter().delete() doesn't raise that exception. Please remove the dead exception handler and instead validate that ids is present/non-empty before deleting.

Suggested change
try:
ids = request.data['ids']
ids_arr = ids.split(',')
Case.objects.filter(id__in=ids_arr).delete()
except Case.DoesNotExist:
return APIResponse(code=1, msg='对象不存在')
ids = request.data.get('ids')
if not ids:
return APIResponse(code=1, msg='ids不能为空')
ids_arr = ids.split(',')
Case.objects.filter(id__in=ids_arr).delete()

Copilot uses AI. Check for mistakes.
return APIResponse(code=0, msg='删除成功')
85 changes: 85 additions & 0 deletions server/myapp/views/admin/download.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Create your views here.

from rest_framework.decorators import api_view, authentication_classes
from rest_framework.pagination import PageNumberPagination

from myapp.auth.authentication import AdminTokenAuthtication
from myapp.handler import APIResponse
from myapp.models import Download
from myapp.permission.permission import isDemoAdminUser, check_if_demo
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isDemoAdminUser is imported but never used in this module. Please remove the unused import to keep the file clean.

Suggested change
from myapp.permission.permission import isDemoAdminUser, check_if_demo
from myapp.permission.permission import check_if_demo

Copilot uses AI. Check for mistakes.
from myapp.serializers import DownloadSerializer
from myapp.utils import after_call, clear_cache


class MyPageNumberPagination(PageNumberPagination):
page_size = 10 # 每页的默认项
page_size_query_param = 'pageSize' # 允许通过 URL 参数设置每页的大小
max_page_size = 100 # 最大页尺寸


@api_view(['GET'])
@authentication_classes([AdminTokenAuthtication])
def list_api(request):
if request.method == 'GET':
download = Download.objects.order_by('-create_time')
total = download.count()

paginator = MyPageNumberPagination()
paginated_download = paginator.paginate_queryset(download, request)
serializer = DownloadSerializer(paginated_download, many=True)
return APIResponse(code=0, msg='查询成功', data=serializer.data, total=total)


@api_view(['POST'])
@authentication_classes([AdminTokenAuthtication])
@check_if_demo
@after_call(clear_cache)
def create(request):

data = request.data.copy()
serializer = DownloadSerializer(data=data)
if serializer.is_valid():
serializer.save()
return APIResponse(code=0, msg='创建成功', data=serializer.data)
else:
print(serializer.errors)

return APIResponse(code=1, msg='创建失败')


@api_view(['POST'])
@authentication_classes([AdminTokenAuthtication])
@check_if_demo
@after_call(clear_cache)
def update(request):

try:
pk = request.data['id']
download = Download.objects.get(pk=pk)
except Download.DoesNotExist:
return APIResponse(code=1, msg='对象不存在')

data = request.data.copy()
serializer = DownloadSerializer(download, data=data)
if serializer.is_valid():
serializer.save()
return APIResponse(code=0, msg='更新成功', data=serializer.data)
else:
print(serializer.errors)
return APIResponse(code=1, msg='更新失败')


@api_view(['POST'])
@authentication_classes([AdminTokenAuthtication])
@check_if_demo
@after_call(clear_cache)
def delete(request):

try:
ids = request.data['ids']
ids_arr = ids.split(',')
Download.objects.filter(id__in=ids_arr).delete()
except Download.DoesNotExist:
return APIResponse(code=1, msg='对象不存在')

Comment on lines +78 to +84
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The try/except Download.DoesNotExist around Download.objects.filter(...).delete() will never catch DoesNotExist because filter().delete() doesn't raise that exception. Please remove the dead exception handler and instead validate that ids is present/non-empty before deleting.

Suggested change
try:
ids = request.data['ids']
ids_arr = ids.split(',')
Download.objects.filter(id__in=ids_arr).delete()
except Download.DoesNotExist:
return APIResponse(code=1, msg='对象不存在')
ids = request.data.get('ids')
if not ids or not str(ids).strip():
return APIResponse(code=1, msg='ids不能为空')
ids_arr = str(ids).split(',')
Download.objects.filter(id__in=ids_arr).delete()

Copilot uses AI. Check for mistakes.
return APIResponse(code=0, msg='删除成功')
Loading