Web实战丨基于Django与HTML的新闻发布系统

news2024/11/16 12:24:49

文章目录

  • 写在前面
  • 项目简介
  • 项目框架
  • 实验内容
    • 安装依赖库
    • 1.创建项目
    • 2.系统配置
    • 3.配置视图文件
    • 4.配置模型文件
    • 5.配置管理员文件
    • 6.配置模板文件
    • 7.创建数据库
    • 8.启动项目
  • 运行结果
  • 写在后面

写在前面

本期内容:基于Django与HTML的简单新闻发布系统。

项目需求:Python+Django

项目下载地址:https://download.csdn.net/download/m0_68111267/88728636

项目简介

本期博主将带着大家用Django完成一个简单的新闻发布系统,该新闻发布系统具有“登录界面”,“注册界面”,“新闻界面”以及“后台界面”。

项目框架

  • 用户注册界面:用户可以注册自己的信息,用于登录系统。
  • 用户登录界面:登录系统的界面,验证用户的登录信息是否合法。
  • 新闻信息界面:展示新闻的信息。
  • 后台管理界面:管理员可以发布新闻,修改和删除新闻信息。

实验内容

安装依赖库

  • Django(如未安装django库,可以运行以下命令进行安装)
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple django

1.创建项目

  1. 使用以下命令新建一个名为newsProject的项目
django-admin startproject newsProject
  1. 进入newsProject项目,使用以下命令新建一个名为news的app
cd newsProject
django-admin startapp news

2.系统配置

  1. 双击打开newsProject文件夹中的settings.py文件

1

  1. INSTALLED_APPS中添加news

2

  1. 双击打开"newsProject"文件夹下的"urls.py"文件,配置项目的导航路径

3

from django.contrib import admin
from django.urls import path
from news import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.home),
    path('regist/', views.regist),
    path('login/', views.login),
    path('logout/', views.logout),
    path('article/', views.article),
    path('<int:id>/', views.detail, name='detail'),
]

注意代码里的views可能会爆红,这是因为我们还没有配置"views"视图文件,下面就让我们一起来配置一下吧~

3.配置视图文件

双击打开"news"目录下的"views.py"文件,配置项目的视图函数

4

from django.shortcuts import render, redirect
from django.http import HttpResponse, Http404
from .models import Article
from django.contrib import auth
from django import forms 
from django.contrib.auth.models import User  


class UserForm(forms.Form):
    username = forms.CharField(label='用户名', max_length=100)
    password = forms.CharField(label='密 码', widget=forms.PasswordInput())

# 主界面
def home(request):
    return render(request, 'home.html')

# 用户注册界面
def regist(request):
    if request.method == 'POST':
        uf = UserForm(request.POST)  # 包含用户名和密码
        if uf.is_valid():
            # 获取表单数据
            username = uf.cleaned_data['username']  # cleaned_data类型是字典,里面是提交成功后的信息
            password = uf.cleaned_data['password']
            # 添加到数据库
            registAdd = None
            try:
                registAdd = User.objects.create_user(username=username, password=password)
                return render(request, 'regists.html', {'registAdd': registAdd})
            except:
                return render(request, 'regists.html', {'registAdd': registAdd, 'username': username})

    else:
        # 如果不是post提交数据,就不传参数创建对象,并将对象返回给前台,直接生成input标签,内容为空
        uf = UserForm()

    return render(request, 'regist.html', {'uf': uf})


def login(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')

        match = auth.authenticate(username=username, password=password)  # 用户认证
        if match is not None:  # 如果数据库里有记录(即与数据库里的数据相匹配或者对应或者符合)
            auth.login(request, match)  # 登陆成功
            return redirect('/', {'user': match})  # 跳转--redirect指从一个旧的url转到一个新的url
        else:  # 数据库里不存在与之对应的数据
            return render(request, 'login.html', {'login_error': '用户名或密码错误'})  # 登录失败
    return render(request, 'login.html')


def logout(request):
    auth.logout(request)
    return render(request, 'home.html')


def article(request):
    article_list = Article.objects.all()
    # QuerySet是一个可遍历结构,包含一个或多个元素,每个元素都是一个Model实例
    # QuerySet类似于Python中的list,list的一些方法QuerySet也有,比如切片,遍历。
    # 每个Model都有一个默认的manager实例,名为objects,QuerySet有两种来源:通过manager的方法得到、通过QuerySet的方法得到。mananger的方法和QuerySet的方法大部分同名,同意思,如filter(),update()等,但也有些不同,如manager有create()、get_or_create(),而QuerySet有delete()等
    return render(request, 'article.html', {'article_list': article_list})


def detail(request, id):
    try:
        article = Article.objects.get(id=id)
        # print type(article)
    except Article.DoesNotExist:
        raise Http404
    return render(request, 'detail.html', locals())

该段代码是一个基于Django框架的用户注册和登录功能实现。主要包含以下几个函数:

  1. home(request): 主界面,渲染home.html模板。

  2. regist(request): 用户注册界面。如果请求为POST方法,从表单中获取用户名和密码,将其添加到数据库中创建新用户。如果注册成功,渲染regists.html模板并传递注册成功的信息。如果注册失败,渲染regists.html模板并传递错误信息。如果请求为GET方法,直接渲染regist.html模板。

  3. login(request): 用户登录界面。如果请求为POST方法,从表单中获取用户名和密码,使用auth.authenticate()函数进行用户认证。如果认证成功,调用auth.login()函数进行登录并重定向到主页。如果认证失败,渲染login.html模板并传递错误信息。

  4. logout(request): 用户注销功能。调用auth.logout()函数进行注销,并渲染home.html模板。

  5. article(request): 文章列表页面。从数据库中获取所有文章对象,并渲染article.html模板并传递文章列表。

  6. detail(request, id): 文章详情页面。根据文章的id从数据库中获取对应的文章对象,并渲染detail.html模板并传递文章对象。

注意:此时的"Article"会爆红,因为我们还没有配置"models.py"模型文件哦

5

4.配置模型文件

接下来我们就来配置"news"的"models.py"模型文件吧

6

from django.db import models

class Article(models.Model):
    title = models.CharField('标题', max_length=256)
    content = models.TextField('内容')
    pub_date = models.DateTimeField('发表时间', auto_now_add=True, editable=True)
    update_time = models.DateTimeField('更新时间', auto_now=True, null=True)

    def __str__(self):
        return self.title

该代码段定义了一个名为Article的模型类,用于表示文章对象。

该模型类继承自Django提供的models.Model基类,以便使用Django的数据库功能。

模型类包含以下几个字段:

  1. title: 标题字段,使用CharField类型,最大长度为256字符。

  2. content: 内容字段,使用TextField类型,可以存储较长的文本内容。

  3. pub_date: 发表时间字段,使用DateTimeField类型,自动记录发表时间,并设置为只读(不可编辑)。

  4. update_time: 更新时间字段,使用DateTimeField类型,自动记录最后更新时间,并在更新时进行更新,允许为空。

模型类还定义了一个__str__()方法,用于在对象被打印或字符串表示时返回标题字段的值。

该模型类的目的是在数据库中创建一个名为Article的表,用于存储文章的相关信息,如标题、内容、发表时间和更新时间等。

通过使用该模型类,可以方便地对文章对象进行创建、查询、更新和删除操作。

5.配置管理员文件

最后我们需要配置一下"news"里的"admin.py"文件

from django.contrib import admin
from news.models import Article
class ArticleAdmin(admin.ModelAdmin):
    list_display = ('title','pub_date', 'update_time',)
admin.site.register(Article, ArticleAdmin)

这段代码是在Django的admin.py文件中注册一个模型(Model)并配置相应的管理选项。

首先,我们导入了admin模块,并导入了Article模型(假设该模型定义在news.models文件中)。

然后,我们定义了一个名为ArticleAdmin的类,继承自admin.ModelAdmin。该类用于配置Article模型在Django admin后台的显示和操作选项。

在这个类中,我们设置了list_display属性,它是一个包含模型字段名称的元组。这个属性指定了在Django admin后台中列表视图显示的字段。在这个例子中,我们指定了’title’(标题)、‘pub_date’(发布日期)和’update_time’(更新时间)。

最后,我们调用admin.site.register()方法,将Article模型和ArticleAdmin类进行注册。这告诉Django admin后台要管理Article模型,并使用ArticleAdmin类中指定的配置选项。

通过这段代码,您就可以在Django admin后台中管理Article模型,并可以根据设置的list_display属性在列表视图中显示指定的字段。

6.配置模板文件

本项目共需要创建六个模板文件,首先我们需要在"news"目录下新建一个"templates"子目录,然后在"templates"目录中创建六个文件(页面):

  • home:主页
<html lang="en">
<head>
    <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="A layout example that shows off a blog page with a list of posts.">

    <title>新闻系统</title>
    <link rel="stylesheet" href="http://labfile.oss.aliyuncs.com/courses/487/pure-min.css">
    <link rel="stylesheet" href="http://labfile.oss.aliyuncs.com/courses/487/grids-responsive-min.css">
    <link rel="stylesheet" href="http://labfile.oss.aliyuncs.com/courses/487/blog.css">

</head>
<body>
<div id="layout" class="pure-g">
    <div class="sidebar pure-u-1 pure-u-md-1-4">
        <div class="header">
            <h1 class="brand-title"><a href="#"> Want595最新要闻</a>

……具体代码需要下载后查看哦~

该HTML模板文件用于渲染新闻系统的页面布局。

页面布局分为两个部分:侧边栏(sidebar)和内容区域(content)。

侧边栏部分包含以下内容:

  1. 网站标题和标语,用<h1><h2>标签进行展示。

  2. 导航栏,包含一个无序列表(<ul>),其中的列表项(<li>)包含以下内容:

    • 如果用户已经登录,显示用户的用户名和一个退出按钮。
    • 如果用户未登录,显示一个注册按钮和一个登录按钮。

内容区域部分使用一个<div>元素包裹,用于渲染具体的页面内容。在模板中使用了一个{% block content %}标签,表示该区域是一个可被子模板继承并填充内容的区域。

该模板文件使用了PureCSS框架提供的样式表,以实现页面的样式和布局。

通过使用该模板文件,可以方便地创建新闻系统的页面布局,并根据具体需求填充和扩展页面内容。

  • regist:用户注册页面
{% extends 'home.html' %}
 
{% block content %}
    <h1>注册页面</h1>
    <form method="POST" enctype="multipart/form-data">
{% csrf_token %}
        {{uf.as_p}}
        <input type="submit" value="OK" />
    </form>
{% endblock %}

这个模板继承自一个名为home.html的父模板,通过{% extends 'home.html' %}指令进行继承。

在模板中使用了一个{% block content %}标签来填充内容,表示该区域是可以被父模板中同名块所替换的区域。

具体内容如下:

  1. 使用<h1>标签显示了一个标题为"注册页面"的标题。

  2. 使用<form>标签创建了一个表单,其中method属性指定了使用POST方法提交表单数据,enctype属性指定了表单数据的编码方式为multipart/form-data

  3. 使用{% csrf_token %}标签生成一个CSRF令牌,用于防止跨站请求伪造。

  4. 使用{{ uf.as_p }}渲染了一个表单对象uf,其中的as_p方法会将表单字段渲染为<p>标签的形式,方便显示字段和输入框。

  5. 使用<input>标签创建了一个类型为"submit"的按钮,显示文本为"OK",用于提交表单。

通过这个模板,可以在注册页面中显示一个表单,接收用户的注册信息,并通过提交按钮将信息发送给服务器进行处理。

  • regists:注册成功或失败页面
{% extends 'home.html' %}
 
{% block content %}
 
{{registAdd}}
 
<br>
================
<br>
{% if username %}
注册失败,{{ username }}已存在!
<a href="/regist">注册</a>
{% else %}
注册成功!
<a href="/login">登录</a>
{% endif %}
 
{% endblock %}

这个模板继承自一个名为home.html的父模板,通过{% extends 'home.html' %}指令进行继承。

在模板中使用了一个{% block content %}标签来填充内容,表示该区域是可以被父模板中同名块所替换的区域。

具体内容如下:

  1. 使用{{registAdd}}语句输出了一个变量registAdd的值。根据上下文来看,这个变量可能是在视图函数中传递给模板的。

  2. 使用<br>标签插入一个换行。

  3. 使用{% if username %}条件语句,判断变量username是否存在。

  4. 如果username存在,输出"注册失败"和username已存在的提示信息,同时提供一个"注册"的链接用于重新注册。

  5. 如果username不存在,输出"注册成功!"的提示信息,同时提供一个"登录"的链接用于跳转到登录页面。

通过这个模板,可以根据不同的情况在注册结果页面显示不同的提示信息,给用户提供相应的操作选项。

  • login:用户登录页面
{% extends 'home.html' %}
 
{% block content %}
 
<div>
        <form action="/login/" method="POST">{% csrf_token %}
            <h2>请登录</h2>
            <input type="text" name="username" />
            <input type="password" name="password" />
            <button type="submit">登录</button>
            <p style="color: red">{{ login_error }}</p>
        </form>
</div>
 
{% endblock %}

这个模板继承自一个名为home.html的父模板,通过{% extends 'home.html' %}指令进行继承。

在模板中使用了一个{% block content %}标签来填充内容,表示该区域是可以被父模板中同名块所替换的区域。

具体内容如下:

  1. 使用<div>元素包裹了一个表单,该表单的提交目标为"/login/",使用POST方法提交数据。

  2. 使用{% csrf_token %}模板标签添加一个跨站请求伪造保护的令牌。

  3. 使用<h2>标签显示"请登录"的标题。

  4. 使用两个<input>标签分别用于输入用户名和密码,分别对应name="username"name="password"

  5. 使用<button>标签显示一个"登录"按钮。

  6. 使用<p>标签显示一个红色文本,该文本内容由login_error变量提供,用于显示登录出现的错误信息。

通过这个模板,用户可以在登录页面输入用户名和密码,并点击登录按钮进行登录操作。如果登录失败,会显示相应的错误信息。

  • article:新闻页面
{% extends 'home.html' %}
 
{% block content %}
 
<h2>新闻列表</h2>
{% for article in article_list %}
    <h3><a href="{% url 'detail' id=article.id %}">{{ article.title }}</a></h3>
{% endfor %}
 
{% endblock %}

这个模板继承自一个名为home.html的父模板,通过{% extends 'home.html' %}指令进行继承。

在模板中使用了一个{% block content %}标签来填充内容,表示该区域是可以被父模板中同名块所替换的区域。

具体内容如下:

  1. 使用<h2>标签显示"新闻列表"的标题。

  2. 使用{% for article in article_list %}模板标签开始一个循环,遍历article_list列表中的每个元素。

  3. 在循环内部,使用<h3>标签显示每篇文章的标题,并且使用{% url 'detail' id=article.id %}生成文章详情页面的链接。

  4. 使用{% endfor %}结束循环。

通过这个模板,可以在页面上显示新闻列表,并且每个新闻标题都有对应的链接可以跳转到相应的新闻详情页面。

  • detail:新闻详情页面
{% extends 'home.html' %}
 
{% block content %}
 
<h2>{{ article.title }}</h2>
 
{{ article.content }}
 
{% endblock %}

这个模板继承自一个名为home.html的父模板,通过{% extends 'home.html' %}指令进行继承。

在模板中使用了一个{% block content %}标签来填充内容,表示该区域是可以被父模板中同名块所替换的区域。

具体内容如下:

  1. 使用<h2>标签显示article对象的标题,通过{{ article.title }}获取到文章标题的值。

  2. 使用{{ article.content }}显示article对象的内容,通过{{ article.content }}获取到文章内容的值。

通过这个模板,可以在页面上显示文章的标题和内容。

7.创建数据库

在终端输入以下命令创建(迁移)数据库

python manage.py makemigrations
python manage.py migrate

8.启动项目

  1. 我们首先需要创建一个超级用户(管理员),用于登录后台
python manage.py createsuperuser
  1. 我创建了一个超级用户admin,并设置密码为123456

7

  1. 在终端输入以下命令启动项目
python manage.py runserver
  1. 如果出现以下网址,说明项目启动成功啦!

8

运行结果

  1. 主页

9

  1. 注册页面

10

  1. 注册成功页面

11

  1. 登录页面

12

  1. 新闻页面

13

  1. 新闻详情页面

14

  1. 管理员页面

15

写在后面

我是一只有趣的兔子,感谢你的喜欢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1376751.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux高级篇基础理论十一(GlusterFS)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️不能因为人生的道路坎坷,就使自己的身躯变得弯曲;不能因为生活的历程漫长,就使求索的 脚步迟缓。 ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xff1a;云计算技…

以用户为导向,可定制化高精度直线模组降本增效正当时

近年来&#xff0c;随着工业自动化转型升级不断提速&#xff0c;市场对优质直线模组的需求量直线上升&#xff0c;而直线模组拥有单体运动速度快、重复定位精度高、本体质量轻、占设备空间小、寿命长等优势&#xff0c;在机械设备领域备受青睐。作为深耕工业自动化产品市场多年…

【Linux驱动】Linux的中断系统 | 中断的重要数据结构

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux驱动》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f3c0;Linux系统的中断⚽中断分类软中断和硬中断中断的上半部和下半部 ⚽tasklet⚽工…

【提示学习论文六】MaPLe: Multi-modal Prompt Learning论文原理

文章目录 MaPLe: Multi-modal Prompt Learning 多模式提示学习文章介绍动机MaPLe:Multi-modal Prompt Learning 模型结构1、Deep Language Prompting 深度语言提示2、Deep Vision Prompting 深度视觉提示3、Vision Language Prompt Coupling 视觉语言提示耦合提示耦合过程 实验…

xtu oj 1520 方程组

题目描述 求 &#xff0c;其中x≤y 的整数解。 输入格式 第一行是一个整数T (1≤T≤1000)&#xff0c;表示样例的个数。 第二行是两个整数n, n∈[−109,109]和m, m∈[0,109]。 输出格式 依次输出一个样例的结果。 输出一行&#xff0c;为两个整数,之间用一个空格隔开;如果…

Word·VBA实现邮件合并

目录 制作邮件合并模板VBA实现邮件合并举例 之前写过的一篇使用《python实现word邮件合并》&#xff0c;本文为vba实现方法 制作邮件合并模板 域名可以使用中文&#xff0c;最终完成的word模板&#xff0c;wps操作步骤类似 VBA实现邮件合并 在Excel启用宏的工作表运行以下代…

Delete `␍`eslint(prettier/prettier)

一、问题&#xff1a; 今天下午配置eslint和prettier 时&#xff0c;频频报错&#xff1a;Delete ␍eslint(prettier/prettier)&#xff0c;vscode全页面爆红。 经过多次尝试与试验后&#xff0c;最终多种方式结合解决了这个问题。 二、报错原因是&#xff1a; 安装了prett…

德思特方案 | 德思特大电流注入测试方案,为电子设备打造电磁干扰“防火墙”

来源&#xff1a;德思特测试测量 德思特方案 | 德思特大电流注入测试方案&#xff0c;为电子设备打造电磁干扰“防火墙” 原文链接&#xff1a;https://mp.weixin.qq.com/s/xyAnXRThBnwa1L3FOuDkDA 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; 简介 在当前电子技…

计算机毕业设计----Springboot农业物资管理系统

项目介绍 农业物资管理系统&#xff0c;管理员可以对角色进行配置&#xff0c;分配用户角色&#xff1b; 主要功能包含&#xff1a;登录、注册、修改密码、零售出库、零售退货、采购订单管理、采购入库管理、采购退货管理、销售管理、财务管理、报表管理、物资管理、基本资料管…

容器扫描Trivy及Trivy-db数据库研究

trivy介绍 Trivy是一个镜像容器扫描工具&#xff0c;用于扫描漏洞和配置错误。 它是一款相当全面且多功能的安全扫描器&#xff0c;支持多种扫描目标&#xff0c;能够弥补市面上常见Web 漏洞扫描工具的不足。 Trivy 可以轻松地通过安装并将二进制文件添加到项目中&#xff0c;…

【qt】opencv导入pro

我的sdk0文件夹在opencv003项目下&#xff0c;使用opencv451 INCLUDEPATH $$PWD/sdk0/opencv/includeCONFIG(release, debug|release) {LIBS -L$$PWD/sdk0/opencv/lib/ -lopencv_world451opencv.files $$PWD/sdk0/opencv/bin/opencv_world451.dllopencv.path $$OUT_PWD/Re…

基于SpringBoot的医护人员排班系统(代码+数据库+文档)

&#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目 希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;一、研究背景 1.1 研究背景 随…

【Linux进程】查看进程fork创建进程

目录 前言 1. 查看进程 2. 通过系统调用创建进程-fork初识 总结 前言 你有没有想过在使用Linux操作系统时&#xff0c;后台运行的程序是如何管理的&#xff1f;在Linux中&#xff0c;进程是一个非常重要的概念。本文将介绍如何查看当前运行的进程&#xff0c;并且讨论如何使用…

概率论与数理统计-第7章 假设检验

假设检验的基本概念 二、假设检验的基本思想 假设检验的基本思想实质上是带有某种概率性质的反证法&#xff0c;为了检验一个假设H0,是否正确&#xff0c;首先假定该假设H0正确&#xff0c;然后根据抽取到的样本对假设H0作出接受或拒绝的决策&#xff0c;如果样本观察值导致了…

【深入挖掘Java技术】「源码原理体系」盲点问题解析之HashMap工作原理全揭秘(上)

HashMap工作原理全揭秘 — 核心源码解析 知识盲点概念介绍数据结构数组链表数组VS链表哈希表不同JVM版本HashMap的展现形式 HashMap VS HashTable特性区别对比 hashcodehashCode的作用equals方法和hashcode的关系key为null怎么办执行步骤 核心参数容量探讨负载因子探讨加载因子…

基于pytorch的循环神经网络情感分析系统

任务目标 基于给定数据集&#xff0c;进行数据预处理&#xff0c;搭建以LSTM为基本单元的模型&#xff0c;以Adam优化器对模型进行训练&#xff0c;使用训练后的模型进行预测并计算预测分类的准确率。 数据简介 IMDB数据集是一个对电影评论标注为正向评论与负向评论的数据集…

【Android开发】不同Activity之间的数据回传实例(一)摘桃子游戏

一、功能介绍 该项目实现的功能主要有&#xff1a; 在首页显示一个按钮点击该按钮跳转到桃园页面在桃园页面&#xff0c;点击桃子会弹窗显示摘到几个桃子&#xff0c;同时被点击桃子消失&#xff0c;总桃子数1点击退出桃园会返回首页&#xff0c;首页桃子数会根据点击的桃子数…

伐木工 - 华为OD统一考试

OD统一考试 题解: Java / Python / C++ 题目描述 一根X米长的树木,伐木工切割成不同长度的木材后进行交易,交易价格为每根木头长度的乘积。规定切割后的每根木头长度都为正整数,也可以不切割,直接拿整根树木进行交易。请问伐木工如何尽量少的切割,才能使收益最大化? 输…

一、docker的安装与踩坑

目录 一、安装docker&#xff08;centos7安装docker&#xff09;1.安装环境前期准备2.参考官网安装前准备3.参考官网安装步骤开始安装docker4.运行首个容器 二、安装一些软件的踩坑1.启动docker踩坑2.安装mysql踩坑3.罕见问题 三、关于我的虚拟机 一、安装docker&#xff08;ce…

销售团队如何实现业绩增长?CRM系统的线索管理功能有什么用?

随着“以客户为中心”观念的逐渐普及&#xff0c;销售团队的客户比过去更复杂&#xff0c;交易周期更久&#xff0c;竞争也更激烈。假如没有明确的销售计划&#xff0c;团队可能陷入混乱&#xff0c;最后导致客户&公司之间的负面结果。在这种情况下&#xff0c;人工智能驱动…