FirstAssignment_832201319尚天翼

832201319尚天翼 2024-10-31 17:52:28

Front-End and Back-End Separation Contacts Programming Assignment

Course for This Assignment2401_MU_SE_FZU
Student IDFZU:832201319 MU:22125329
Assignment RequirementsDesign a front-end and back-end separated contact
Objectives of This AssignmentExercise independent learning ability and learn the basic knowledge of software development

Git Repository Link and Code Standards

Assignment Description

This assignment requires the development of a contact management system with a clear separation between the front-end and back-end components. The application must support basic CRUD (Create, Read, Update, Delete) operations on contact information, allowing users to manage contact data stored in a back-end database. Here are the main requirements and goals:

  1. Core Functionalities:

    • Add Contact: Allows users to create new contacts with details such as name, gender, phone number, and remarks.

    • Modify Contact: Enables editing of contact details by retrieving the current data directly from the database.

    • Delete Contact: Provides the option to delete contacts from the database.

    • View Contacts(Additional Features): Retrieves and displays all contacts stored in the back-end database.

  2. Front-End Requirements:

    • Develop an interactive user interface that allows users to add, edit, delete, and view contacts.

    • Use HTML, CSS, and JavaScript to build the UI, ensuring that it communicates with the back end through RESTful API calls.

  3. Back-End Requirements:

    • Implement the back-end using Spring Boot, ensuring it provides RESTful APIs to support all required operations.

    • Use Java and JPA (Java Persistence API) for database operations, with a Contact entity that includes fields for ID, name, gender, phone number, and remarks

    The main objective is to develop a functional, interactive, and scalable contact management system while practicing full-stack development principles with front-end and back-end separation.

 

PSP Table

TaskEstimated Time (hours)Actual Time (hours)
Requirement Analysis22
Design22.5
Front-End Development67
Back-End Development88.5
Testing22.5
Deployment11
Documentation and Blogging11
Total2224.5

 

Present Finished Product

1. Add

Initially, there is no contact information in either our database or the front-end page.

 

Then, we click the add button at the top right corner of the front-end page to open the add contact modal. We enter the relevant information and then click save.

 

The contact information appears on both the front-end page and in the database, indicating that the addition was successful.

 

2. Modify

On the front-end page, click the three dots in the top right corner of a contact to open the delete and edit menu.

 

Click edit, modify the contact information in the popup modal, and then click confirm.

 

The content on both the front-end page and in the database has been successfully updated.

 

3. Delete

On the front-end page, click the three dots in the top right corner of a contact to open the delete and edit menu, and then click delete.

 

The contact has been successfully deleted from both the front-end page and the database.

 

 

4. display

When multiple contacts exist in the database, we use a display function to show all contact information on the front-end page, allowing users to add, delete, view, and modify multiple contacts.

 

 

Design and Implementation Process

  1. Requirements Gathering

    • Identify the core objectives and functionalities of the software.

    • Engage stakeholders through interviews and surveys to gather insights on user needs.

    • Document use cases to understand user interactions with the system.

  2. System Design

    • Architecture Design: Choose an architectural style (e.g., microservices, monolithic) that best fits the project requirements.

    • Database Design: Create an Entity-Relationship Diagram (ERD) to define the data structure, relationships, and constraints. Choose a suitable database management system (SQL or NoSQL).

    • User Interface (UI) Design: Develop wireframes and mockups using tools like Figma or Adobe XD. Focus on usability, accessibility, and aesthetics.

  3. Functional Specification

    • Develop a detailed functional specification document that describes each feature, its inputs, outputs, and how it interacts with other components.

    • Define performance requirements and security measures, ensuring data protection and compliance with regulations.

  4. Implementation

    • Development Environment Setup: Configure the necessary development tools, version control systems (e.g., Git), and project management software (e.g., Jira).

    • Coding: Follow coding standards and guidelines. Implement features in iterative cycles (sprints), focusing on unit tests to ensure code quality.

    • Integration: Continuously integrate and test components as they are developed. Use Continuous Integration/Continuous Deployment (CI/CD) tools to automate the deployment process.

  5. Testing

    • Conduct various testing phases: unit testing, integration testing, system testing, and user acceptance testing (UAT).

    • Identify and fix bugs or issues found during testing to ensure functionality and performance meet the specified requirements.

  6. Deployment

    • Prepare for deployment by creating deployment scripts and ensuring all configurations are correct.

    • Deploy the application in a production environment. Monitor system performance and resolve any post-deployment issues.

  7. Maintenance and Updates

    • Continuously monitor the application for bugs and performance issues. Provide regular updates and enhancements based on user feedback.

    • Plan for periodic evaluations to adapt the software to changing requirements or technological advancements.

Functional Structure Diagram

The functional structure diagram outlines the main components and their relationships within the system. Below is a simplified example of how such a diagram might look:

 

 

Explanation of Components

  1. User Interface: This is the layer that interacts directly with the users. It can be a web application, mobile app, or both, designed based on the UI/UX guidelines established in the design phase.

  2. Application Server: This layer handles requests from the user interface and routes them to the appropriate services. It serves as a mediator between the frontend and the business logic layer.

  3. Business Logic Layer: This component contains the core functionality of the application, implementing the business rules and workflows as defined in the functional specifications.

  4. Data Access Layer: Responsible for communication with the database. This layer abstracts the details of data storage and retrieval, allowing for easier maintenance and potential changes to the database system.

  5. Database: The backend data storage system where all application data is stored, managed, and retrieved.

     

Code explanation

backend:

package com.sty.entity;
​
import javax.persistence.*;
​
@Entity
public class Contact {
​
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
​
    private String name;
    private String gender;
    private String phoneNumber;
    // 添加 remarks 字段
    private String remarks;
​
    // Constructors, Getters, and Setters
​
    public Contact() {}
​
    public Contact(String name, String phoneNumber, String remarks,String gender) {
        this.name = name;
        this.phoneNumber = phoneNumber;
        this.remarks = remarks;
        this.gender = gender;
    }
​
    public Long getId() {
        return id;
    }
​
    public void setId(Long id) {
        this.id = id;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public String getPhoneNumber() {
        return phoneNumber;
    }
​
    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }
​
    public String getRemarks() {
        return remarks;
    }
​
    public void setRemarks(String remarks) {
        this.remarks = remarks;
    }
​
    public String getGender() {
        return gender;
    }
​
    public void setGender(String gender) {
        this.gender = gender;
    }
}

This code defines a contact entity class Contact, which includes basic information (name, gender, phone number, and remarks) as well as necessary constructors and access methods. Through JPA annotations, it can interact with the database for persistence operations. This class serves as the foundation for building applications related to contacts.

package com.sty.service;
​
import com.sty.entity.Contact;
import com.sty.respository.ContactRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
​
import java.util.List;
import java.util.Optional;
​
@Service
public class ContactService {
​
    @Autowired
    private ContactRepository contactRepository;
​
    // 添加联系人
    public Contact addContact(Contact contact) {
        return contactRepository.save(contact);
    }
​
    // 修改联系人
    public Contact updateContact(Long id, Contact contactDetails) {
        Optional<Contact> optionalContact = contactRepository.findById(id);
        if (optionalContact.isPresent()) {
            Contact contact = optionalContact.get();
            contact.setName(contactDetails.getName());
            contact.setGender(contactDetails.getGender());
            contact.setPhoneNumber(contactDetails.getPhoneNumber());
            contact.setRemarks(contactDetails.getRemarks());
            return contactRepository.save(contact);
        } else {
            throw new RuntimeException("Contact not found");
        }
    }
​
    // 删除联系人
    public void deleteContact(Long id) {
        if (contactRepository.existsById(id)) {
            contactRepository.deleteById(id);
        } else {
            throw new RuntimeException("Contact not found");
        }
    }
​
    // 获取所有联系人
    public List<Contact> getAllContacts() {
        return contactRepository.findAll();
    }
​
    // 根据ID获取联系人
    public Contact getContactById(Long id) {
        return contactRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Contact not found"));
    }
}

This code defines a ContactService class that acts as a service layer for managing contact entities in a Spring application. It uses the ContactRepository to perform CRUD operations. The class includes methods to add a contact, update an existing contact by ID, delete a contact, retrieve all contacts, and find a contact by ID. Each method handles potential errors, such as when a contact is not found, by throwing a runtime exception. The @Service annotation indicates that this class is a Spring service component, and the @Autowired annotation allows for automatic dependency injection of the ContactRepository.

 

package com.sty.respository;
​
import com.sty.entity.Contact;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
​
@Repository
public interface ContactRepository extends JpaRepository<Contact, Long> {
}

This code defines a ContactRepository interface that extends JpaRepository, providing a data access layer for the Contact entity. By extending JpaRepository, it inherits various methods for CRUD operations and database interactions without needing to implement them manually. The generic parameters specify that the repository will work with Contact entities and that the type of the primary key is Long. The @Repository annotation indicates that this interface is a Spring Data repository, allowing it to be automatically detected and utilized by the Spring framework for data operations.

package com.sty.controller;
​
import com.sty.entity.Contact;
import com.sty.service.ContactService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
​
import java.util.List;
@CrossOrigin(origins = "*", methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE})
@RestController
@RequestMapping("/api/contacts")
public class ContactController {
​
    @Autowired
    private ContactService contactService;
​
    // 添加联系人
    @PostMapping("/add")
    public ResponseEntity<Contact> addContact(@RequestBody Contact contact) {
        Contact newContact = contactService.addContact(contact);
        return ResponseEntity.ok(newContact);
    }
​
    // 修改联系人
    @PutMapping("/modify/{id}")
    public ResponseEntity<Contact> modifyContact(@PathVariable Long id, @RequestBody Contact contactDetails) {
        Contact updatedContact = contactService.updateContact(id, contactDetails);
        return ResponseEntity.ok(updatedContact);
    }
​
    // 删除联系人
    @DeleteMapping("/delete/{id}")
    public ResponseEntity<String> deleteContact(@PathVariable Long id) {
        contactService.deleteContact(id);
        return ResponseEntity.ok("Contact deleted successfully");
    }
​
    // 获取所有联系人
    @GetMapping("/all")
    public ResponseEntity<List<Contact>> getAllContacts() {
        List<Contact> contacts = contactService.getAllContacts();
        return ResponseEntity.ok(contacts);
    }
​
    // 根据ID获取联系人
    @GetMapping("/{id}")
    public ResponseEntity<Contact> getContactById(@PathVariable Long id) {
        Contact contact = contactService.getContactById(id);
        return ResponseEntity.ok(contact);
    }
}

This code defines a ContactController class, which serves as a RESTful API controller for managing contact entities in a Spring application. It is annotated with @RestController to indicate that it handles HTTP requests and responses. The @RequestMapping("/api/contacts") annotation sets the base URL for all endpoints in this controller.

The class uses @Autowired to inject the ContactService, which provides the business logic for handling contact operations. The controller includes several endpoint methods:

  1. addContact: Handles POST requests to add a new contact, receiving a Contact object in the request body and returning the created contact.

  2. modifyContact: Handles PUT requests to update an existing contact by ID, using the ID from the URL path and the updated details from the request body.

  3. deleteContact: Handles DELETE requests to remove a contact by ID, returning a success message upon completion.

  4. getAllContacts: Handles GET requests to retrieve a list of all contacts.

  5. getContactById: Handles GET requests to fetch a specific contact by its ID.

The @CrossOrigin annotation allows cross-origin requests, making the API accessible from different domains. Each method returns a ResponseEntity, encapsulating the HTTP response and allowing for proper status codes and payloads.

 

FrontEnd:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>App</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="./index.css">
</head>
<body>
<div id="mask" class="disableAddModal">
    <div id="panel">
        <div id="avatar"></div>
        <p id="random">随机头像</p>
        <input type="text" id="name" placeholder="请输入姓名">
        <input type="text" id="gender" placeholder="请输入性别">
        <input type="text" id="phoneNumber" placeholder="请输入电话号码">
        <input type="text" id="remarks" placeholder="请输入备注">
        <div id="save">保存</div>
        <div id="cancel">取消</div>
    </div>
</div>
<div id="header">
    <h1 id="title">通信录</h1>
    <img id="add" src="./img/add.png" alt="" />
</div>
<p id="tip">
    当前没有任何联系人<br />
    请点击右上角添加
</p>
<div id="content">
    <div id="template" class="card" style="display:none;">
        <div class="avatar"></div>
        <div class="group">
            <p class="name">姓名</p>
            <p class="gender">性别</p>
            <p class="phoneNumber">电话号码</p>
            <p class="remarks">备注</p>
        </div>
        <img src="./img/more.png" alt="" class="more">
        <div class="expand">
            <div class="edit">修改</div>
            <div class="line"></div>
            <div class="delete">删除</div>
        </div>
    </div>
</div>
​
<!-- 引入修改后的 JavaScript 文件 -->
<script src="./index1.js"></script>
</body>
</html>

This code defines the structure of an HTML page for a contact management application. It includes several key components:

  1. Document Structure: The <!DOCTYPE html> declaration indicates that this is an HTML5 document, with the html tag setting the language to English.

  2. Head Section: The <head> section contains metadata, including character encoding (UTF-8), the page title ("App"), viewport settings for responsive design, and a link to an external CSS stylesheet (index.css) for styling.

  3. Body Content:

    • Modal for Adding Contacts: A div with the ID mask serves as a modal for adding a new contact, which includes input fields for the contact's name, gender, phone number, and remarks, along with buttons to save or cancel the action.

    • Header: Contains a title ("通信录" or "Contacts") and an "add" button represented by an image.

    • Tip Message: A paragraph indicating that there are currently no contacts and prompting the user to add one.

    • Content Section: A div for displaying contact cards, which includes a template for each contact. This template, initially hidden, has fields for displaying the contact's avatar, name, gender, phone number, and remarks, along with buttons for editing and deleting the contact.

  4. Script Inclusion: The page includes an external JavaScript file (index1.js) for implementing functionality, such as handling user interactions and managing contacts.

Overall, this HTML structure sets up a user interface for a contact management app, allowing users to view, add, edit, and delete contacts.

 

 

 

BODY,
HTML {
    width: 100%;
    height: 100%;
    margin: 0px;
    font-family: "PingFang SC", "微软雅黑", sans-serif;
    font-weight: 300;
    color: #333;
}
​
.header {
    width: 100%;
    padding: 32px;
}
​
h1 {
    margin: 32px;
    float: left;
    font-weight: 300;
    font-size: 24px;
}
​
#add {
    margin: 32px;
    margin-top: 38px;
    float: right;
    width: 24px;
}
​
#tip {
    width: 100%;
    text-align: center;
    position: fixed;
    top: 240px;
    color: #9E9E9E;
}
​
#mask {
    position: fixed;
    width: 100%;
    height: 100%;
    background: rgba(33, 33, 33, 0.72);
    z-index: 999;
    display: flex;
    justify-content: center;
    align-items: center;
    transition: all 500ms;
}
​
#panel {
    width: 330px;
    background: #FFF;
    border-radius: 10px;
    box-shadow: 0 15px 30px 0 rgba(0, 0, 0, 0.08),
    0 4px 8px 0 rgba(0, 0, 0, 0.08);
    text-align: center;
    padding-bottom: 24px;
    transition: all 300ms;
}
​
#avatar {
    margin: 0px auto;
    margin-top: -48px;
    width: 96px;
    height: 96px;
    border-radius: 50%;
    background: #FFF;
    background-size: cover !important;
    border: 2px solid #FFFFFF;
    box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.12);
    transition: all 500ms;
}
​
#random {
    color: #4A90E2;
    text-decoration: underline;
}
​
input {
    margin: 0px;
    width: 80%;
    background: #FFFFFF;
    border: 2px solid #EEEEEE;
    border-radius: 10px;
    font-size: 16px;
    padding: 12px 16px;
    outline: none;
    transition: all 500ms;
    margin-top: 8px;
}
​
input:first-child {
    margin-top: 24px;
}
​
input:focus {
    border: 2px solid #4A90E2;
}
​
#save {
    width: 26%;
    background: #4A90E2;
    border-radius: 10px;
    padding: 12px;
    color: #FFF;
    margin-top: 24px;
    float: left;
    margin-left: 48px;
    cursor: pointer;
}
​
#cancel {
    width: 26%;
    background: #EEEEEE;
    border-radius: 10px;
    padding: 12px;
    color: #333;
    margin-top: 24px;
    float: right;
    margin-right: 48px;
    cursor: pointer;
}
​
/* 禁用鼠标 */
.disableAddModal {
    background: rgba(33, 33, 33, 0) !important;
    pointer-events: none;
}
​
/* 完全透明 */
.disableAddModal #panel {
    transform: scale(0.9);
    opacity: 0;
}
​
#content {
    padding: 16px;
    padding-top: 97px;
}
​
.card {
    margin-top: 8px;
    width: 100%;
    height: 110px;  /* 增大高度以适应内容 */
    background: #FFFFFF;
    box-shadow: 0 15px 30px 0 rgba(0, 0, 0, 0.08),
    0 4px 8px 0 rgba(0, 0, 0, 0.08);
    border-radius: 10px;
    overflow: hidden;
    position: relative;
    transition: all 300ms;
}
​
.card_expand {
    height: 160px !important;
}
​
.card_expand .expand {
    margin-top: 16px !important;
}
​
.avatar {
    margin-top: 24px;
    margin-left: 24px;
    float: left;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: #9E9E9E;
    background-size: cover !important;
    border: 2px solid #FFFFFF;
    border: 3px solid #EEEEEE;
}
​
/* 使用 Grid 布局确保内容对齐 */
.group {
    margin-left: 16px;
    margin-top: 24px;
    float: left;
    display: grid;  /* 启用 Grid 布局 */
    grid-template-columns: 1fr 1fr 1fr 1fr;  /* 四列均分 */
    column-gap: 16px;  /* 设置列之间的间距 */
    align-items: center;  /* 垂直方向居中对齐 */
    width: calc(100% - 120px);  /* 动态计算宽度 */
}
​
.group p {
    margin: 0;  /* 移除默认 margin */
    padding: 8px 0;  /* 添加上下内边距 */
    font-size: 18px;  /* 设置字体大小 */
    line-height: 24px;  /* 设置行高,确保垂直居中 */
    color: #333;  /* 文本颜色 */
    text-align: center;  /* 文本居中对齐 */
    overflow: hidden;  /* 隐藏溢出文本 */
    text-overflow: ellipsis;  /* 溢出时显示省略号 */
    white-space: nowrap;  /* 禁止换行 */
}
​
.info {
    color: #666;
}
​
.number {
    color: #4A90E2;
}
​
.description {
    color: #9E9E9E;
}
​
.more {
    position: absolute;
    top: 16px;
    right: 16px;
    width: 24px;
    cursor: pointer;
}
​
.expand {
    width: 100%;
    float: left;
    margin-top: 24px;
}
​
.edit {
    text-align: center;
    vertical-align: middle;
    display: flex;
    align-items: center;
    justify-content: center;
    background: url("./img/edit.png");
    background-size: cover;
    float: left;
    width: 50%;
    height: 43px;
    cursor: pointer;
    transition: all 200ms;
}
​
.edit:hover {
    background: url("./img/edit-active.png");
    background-size: cover;
}
​
.delete {
    background: url("./img/delete.png");
    background-size: cover;
    float: right;
    width: 50%;
    height: 43px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 200ms;
}
​
.delete:hover {
    background: url("./img/delete-active.png");
    background-size: cover;
}
​
.line {
    float: left;
    height: 24px;
    border-right: #EEE 1px solid;
    margin-left: -1px;
    margin-top: 8px;
}

This code is a CSS stylesheet that defines the styles for a web page layout. Here’s a breakdown of its key components:

  1. General Styles:

    • Sets the overall width and height of the BODY and HTML elements to 100%, removes default margins, and applies a specific font family and color.

  2. Header Styles:

    • .header: Full-width with padding.

    • h1: Custom margins, font size, and weight.

  3. Button and Input Styles:

    • #add, #save, and #cancel: Positioned elements with specific margins, sizes, colors, and cursor styles.

    • input: Styles for input fields, including focus effects and padding.

  4. Modal and Panel Styles:

    • #mask and #panel: Styles for a modal overlay and content panel, including positioning, backgrounds, shadows, and transitions.

  5. Card and Content Styles:

    • .card: Card components with set heights, shadows, rounded corners, and transitions.

    • .group: Uses CSS Grid to layout content in four equal columns with spacing.

  6. Text and Description Styles:

    • Various classes for text, like .info, .number, and .description, to style color and alignment.

  7. Interactive Elements:

    • .edit and .delete: Styles for buttons with background images that change on hover.

  8. Miscellaneous:

    • .line: A vertical separator styled with a border.

The stylesheet emphasizes a clean, modern design with responsive layouts and hover effects, enhancing user interaction and readability.

// index1.js
​
document.addEventListener('DOMContentLoaded', function () {
    var DOM = {
        mask: document.getElementById('mask'),
        add: document.getElementById('add'),
        avatar: document.getElementById('avatar'),
        name: document.getElementById('name'),
        gender: document.getElementById('gender'),
        phoneNumber: document.getElementById('phoneNumber'),
        remarks: document.getElementById('remarks'),
        save: document.getElementById('save'),
        cancel: document.getElementById('cancel'),
        random: document.getElementById('random'),
        content: document.getElementById('content'),
        template: document.getElementById('template'),
        tip: document.getElementById('tip'),
    };
​
    var nowNode;
    const API_BASE_URL = 'http://localhost:8080/api/contacts';
​
    // 控制模态框的显示与隐藏
    function disableAddModal(show) {
        if (show) {
            DOM.mask.className = '';
            DOM.avatar.style.backgroundImage =
                "url('./avatar/" + Math.floor(Math.random() * 47) + ".jpg')";
            // 如果是编辑模式,保留原有信息
            if (!nowNode) {
                DOM.name.value = '';
                DOM.gender.value = '';
                DOM.phoneNumber.value = '';
                DOM.remarks.value = '';
            }
        } else {
            DOM.mask.className = 'disableAddModal';
        }
    }
​
    // 添加新联系人按钮事件
    DOM.add.addEventListener('click', function () {
        nowNode = undefined;
        disableAddModal(true);
    });
​
    // 关闭模态框
    DOM.cancel.addEventListener('click', function () {
        nowNode = undefined;
        disableAddModal(false);
    });
​
    // 随机生成头像
    DOM.random.addEventListener('click', function () {
        DOM.avatar.style.backgroundImage =
            "url('./avatar/" + Math.floor(Math.random() * 47) + ".jpg')";
    });
​
    // 切换卡片展开状态
    function expand(element) {
        element.parentNode.classList.toggle('card_expand');
    }
​
    // 编辑联系人
    function edit(node) {
        nowNode = node;
        disableAddModal(true);
        DOM.avatar.style.backgroundImage = node.querySelector('.avatar').style.backgroundImage;
        DOM.name.value = node.querySelector('.name').innerText;
        DOM.gender.value = node.querySelector('.gender').innerText;
        DOM.phoneNumber.value = node.querySelector('.phoneNumber').innerText;
        DOM.remarks.value = node.querySelector('.remarks').innerText;
    }
​
    // 删除联系人
    function remove(node) {
        const contactId = node.dataset.id;
        fetch(API_BASE_URL + '/delete/' + contactId, {
            method: 'DELETE'
        })
            .then(response => {
                if (response.ok) {
                    node.remove();
                    if (DOM.content.children.length === 1) {
                        DOM.tip.style.display = 'block';
                    }
                } else {
                    console.error('Failed to delete contact');
                }
            })
            .catch(error => {
                console.error('Error deleting contact:', error);
            });
    }
​
    // 保存联系人(添加或修改)
    DOM.save.addEventListener('click', function () {
        const contactData = {
            name: DOM.name.value,
            gender: DOM.gender.value,
            phoneNumber: DOM.phoneNumber.value,
            remarks: DOM.remarks.value
        };
​
        if (nowNode) {
            // 更新联系人
            const contactId = nowNode.dataset.id;
            fetch(API_BASE_URL + '/modify/' + contactId, {
                method: 'PUT',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(contactData)
            })
                .then(response => response.json())
                .then(updatedContact => {
                    // 更新界面
                    nowNode.querySelector('.name').innerText = updatedContact.name;
                    nowNode.querySelector('.gender').innerText = updatedContact.gender;
                    nowNode.querySelector('.phoneNumber').innerText = updatedContact.phoneNumber;
                    nowNode.querySelector('.remarks').innerText = updatedContact.remarks;
                    disableAddModal(false);
                    nowNode = undefined;
                })
                .catch(error => {
                    console.error('Error updating contact:', error);
                });
        } else {
            // 添加新联系人
            fetch(API_BASE_URL + '/add', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(contactData)
            })
                .then(response => response.json())
                .then(newContact => {
                    // 创建新节点并添加到界面
                    const node = DOM.template.cloneNode(true);
                    node.style.display = 'block';
                    node.removeAttribute('id');
                    node.dataset.id = newContact.id;
                    node.querySelector('.name').innerText = newContact.name;
                    node.querySelector('.gender').innerText = newContact.gender;
                    node.querySelector('.phoneNumber').innerText = newContact.phoneNumber;
                    node.querySelector('.remarks').innerText = newContact.remarks;
                    node.querySelector('.avatar').style.backgroundImage = DOM.avatar.style.backgroundImage;
​
                    // 添加事件监听器
                    node.querySelector('.more').addEventListener('click', function () {
                        expand(this);
                    });
                    node.querySelector('.edit').addEventListener('click', function () {
                        edit(node);
                    });
                    node.querySelector('.delete').addEventListener('click', function () {
                        remove(node);
                    });
​
                    DOM.content.appendChild(node);
                    disableAddModal(false);
                    if (DOM.content.children.length > 1) {
                        DOM.tip.style.display = 'none';
                    }
                })
                .catch(error => {
                    console.error('Error adding contact:', error);
                });
        }
    });
​
    // 从后端获取所有联系人并渲染
    function fetchContacts() {
        fetch(API_BASE_URL + '/all')
            .then(response => {
                if (!response.ok) {
                    throw new Error('网络响应失败,状态码:' + response.status);
                }
                return response.json();
            })
            .then(data => {
                renderContacts(data);
            })
            .catch(error => {
                console.error('Error fetching contacts:', error);
                alert('获取联系人列表失败:' + error.message);
            });
    }
​
    // 渲染联系人列表
    function renderContacts(contacts) {
        DOM.content.innerHTML = ''; // 清空内容
        if (contacts.length === 0) {
            DOM.tip.style.display = 'block';
        } else {
            DOM.tip.style.display = 'none';
        }
        contacts.forEach(contact => {
            const node = DOM.template.cloneNode(true);
            node.style.display = 'block';
            node.removeAttribute('id');
            node.dataset.id = contact.id;
            node.querySelector('.name').innerText = contact.name;
            node.querySelector('.gender').innerText = contact.gender;
            node.querySelector('.phoneNumber').innerText = contact.phoneNumber;
            node.querySelector('.remarks').innerText = contact.remarks;
            node.querySelector('.avatar').style.backgroundImage = `url('./avatar/${Math.floor(Math.random() * 47)}.jpg')`;
​
            // 添加事件监听器
            node.querySelector('.more').addEventListener('click', function () {
                expand(this);
            });
            node.querySelector('.edit').addEventListener('click', function () {
                edit(node);
            });
            node.querySelector('.delete').addEventListener('click', function () {
                remove(node);
            });
​
            DOM.content.appendChild(node);
        });
    }
​
    // 页面加载时获取联系人列表
    fetchContacts();
});

This JavaScript code manages a contact management interface on a web page. Here’s a breakdown of its functionality:

  1. DOM Elements:

    • The code initializes a DOM object that references various elements in the HTML (like modal mask, buttons, input fields, and content area) for easy access.

  2. API Base URL:

    • A constant API_BASE_URL is defined for making API requests to a local server managing contacts.

  3. Modal Control:

    • The disableAddModal function shows or hides a modal for adding/editing contacts. It sets the avatar to a random image if a new contact is being added and clears input fields unless editing an existing contact.

  4. Event Listeners:

    • Add Button: Opens the modal for adding a new contact.

    • Cancel Button: Closes the modal without saving changes.

    • Random Avatar Button: Changes the avatar to a new random image.

  5. Contact Editing and Removal:

    • The edit function pre-fills the modal with the selected contact's details.

    • The remove function deletes a contact using a DELETE request to the server and removes it from the DOM.

  6. Saving Contacts:

    • The save button handles both adding new contacts and updating existing ones. It sends the appropriate API request (POST for adding, PUT for updating) and updates the displayed contact information accordingly.

  7. Fetching Contacts:

    • The fetchContacts function retrieves all contacts from the server and renders them in the UI.

    • The renderContacts function populates the content area with contact cards and sets up event listeners for each card's actions (expand, edit, delete).

  8. Initialization:

    • The script fetches the contact list when the page loads, ensuring that the UI is populated with existing data.

Overall, this code provides a dynamic and interactive contact management system, enabling users to add, edit, delete, and view contacts seamlessly.

Personal Journey and Learnings

This project helped solidify my understanding of full-stack development, particularly in managing separated front and back ends. Challenges included synchronizing data updates and ensuring cross-origin communication, which were resolved by configuring CORS in the Spring Boot application.

...全文
38 回复 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

170

社区成员

发帖
与我相关
我的任务
社区描述
2401_MU_SE_FZU
软件工程 高校
社区管理员
  • FZU_SE_TeacherL
  • 助教-吴可仪
  • 助教-孔志豪
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧