170
社区成员
Assignment 1 | Front-end and Back-end Separation Contacts Programming |
---|---|
Course for This Assignment | 2401_MU_SE_FZU |
Assignment Requirements | First Assignment -- Front-end and Back-end Separation Contacts Programming |
Name | Rongcheng Xie |
Objectives of This Assignment | develop a contacts mini-program |
Other Reference | WeChat Developer Tools - WeChat Mini Program Design Guide - Javascript Style Guide |
complete code | Complete code demo |
front-end | front-end code |
back-end | back-end code |
@
The core function of the project implements a front-end and back-end separation architecture, which not only makes the development more modular and maintainable, but also provides higher flexibility for function expansion and data processing. In the front end, the small program interface design is simple and clear, focusing on user experience; In the back-end, API is used to realize the function of adding, deleting, checking and changing data, so as to ensure the real-time performance and consistency of data.
Personal Software Process Stages | Estimated Time (minutes) | Actual Time (minutes) |
---|---|---|
Planning | 150 | 120 |
• Estimate | 150 | 120 |
Development | 1050 | 880 |
• Analysis | 150 | 120 |
• Design Spec | 120 | 90 |
• Design Review | 60 | 50 |
• Coding Standard | 40 | 30 |
• Design | 120 | 100 |
• Coding | 300 | 250 |
• Code Review | 50 | 40 |
• Test | 60 | 80 |
Reporting | 300 | 200 |
• Test Report | 80 | 50 |
• Size Measurement | 60 | 40 |
• Postmortem & Process Improvement Plan | 160 | 110 |
Total | 1500 | 1200 |
Wechat mini program entrance, click "小小烧鱼通讯录“” to enter
![mini program](https://i-blog.csdnimg.cn/direct/c9a69c2edff44159a43abe5f0b06d011.png#pic_center =330x680)
You will see the following user interface:
![用户界面](https://i-blog.csdnimg.cn/direct/e7fc4f4f80eb426d853e9cddaed0bb67.gif#pic_center =330x680)
Click the blue "Add User" button in the top-right corner to enter the user addition interface.
![添加按钮](https://i-blog.csdnimg.cn/direct/abbed724a9ef4af8a4e4bc6d6ccfcffa.png#pic_center =330x680)
The mini program will allow adding new contact information, and we can input and save the contact information to the user interface:
![添加联系人](https://i-blog.csdnimg.cn/direct/e6b0045690c2439aacda3c896884edbb.gif#pic_center =330x680)
After adding the operation, the data in the Mini Program Cloud Development Console:
Click the Edit Contact button at the bottom of the screen:
![修改联系人](https://i-blog.csdnimg.cn/direct/9bbb5300e80d47a7aeb0e98d2e7d7dc6.png#pic_center =330x680)
The mini program will allow modifying contact information:
![修改步骤](https://i-blog.csdnimg.cn/direct/1f9a79fd7b2a4304a58a87142216cf70.gif#pic_center =330x680)
After modifying the operation, the data in the Mini Program Cloud Development Console:
Click the Delete Contact button at the bottom of the screen:
![删除按钮](https://i-blog.csdnimg.cn/direct/893ea05c60f241fd82c90adaee379290.png#pic_center =330x680)
The mini program will allow deleting contact information:
![删除顺序](https://i-blog.csdnimg.cn/direct/ff2198412f994a0ea6f14a9dd68ab6c3.gif#pic_center =330x680)
After deleting the operation, the data in the Mini Program Cloud Development Console:
Can search for contacts based on key letters entered
![搜索功能](https://i-blog.csdnimg.cn/direct/7ba122b972574c28aa60bf2a4c329c26.gif#pic_center =330x680)
After clicking Upload the avatar, you can choose to take a photo or choose from an album:
![头像选择](https://i-blog.csdnimg.cn/direct/8ffb91311f78478eb80098233a0bf2db.gif#pic_center =330x680)
Here's some important code:
<!-- index界面 -->
<!-- navi -->
<view class="navi">
<view class="navitext">
<text class="scrolling-text">小小烧鱼</text>
<text class="static-text">通讯录</text>
</view>
<view class="add-circle" bindtap="onAddContact">
<text class="add-text">+</text>
</view>
</view>
<!-- 搜索框独立图层 -->
<view class="search-container">
<input class="search-input" placeholder="搜索联系人" bindinput="onSearchInput" />
</view>
<!-- contact -->
<scroll-view class="contact"
scroll-y="true"
scroll-into-view="{{loc}}"
style="height: {{screenHeight}}rpx; position: relative; left: 0rpx; top: 427rpx"
scroll-with-animation="true">
<block wx:for="{{filteredContacts}}" wx:key="letter">
<view class="group" wx:if="{{item.group.length != 0}}" id="{{item.letter}}">
<view class="header">{{item.letter}}</view>
<navigator class="card"
wx:for="{{item.group}}"
wx:for-item="star"
wx:key="*this"
url="/pages/card/card?id={{star._id}}">
<view class="name">{{star.name}}</view>
</navigator>
<view class="line"></view>
</view>
<view wx:else id="{{item.letter}}"></view>
</block>
</scroll-view>
<!-- 右侧字母栏 -->
<view class="shortcut">
<view class="letter" wx:for="{{letters}}" wx:key="*this" bindtap="onTapScroll" data-loc="{{item}}">
{{item}}
</view>
</view>
<!-- card界面展示 -->
<view class="contact-detail">
<!-- 圆形头像区域 -->
<view class="avatar-section" bindtap="onSelectPhoto">
<image class="avatar" src="{{contact.avatar || '/img/default-avatar.png'}}" mode="aspectFill" />
<text class="select-text" wx:if="{{!contact.avatar}}">选择头像</text>
</view>
<!-- 联系人基本信息 -->
<view class="info-section">
<view class="field editable">
<view class="label">姓名:</view>
<input class="value" value="{{contact.name}}" disabled="{{!isEditing}}" bindinput="onNameInput" />
</view>
<view class="field editable">
<view class="label">电话:</view>
<input class="value" value="{{contact.phone}}" disabled="{{!isEditing}}" bindinput="onPhoneInput" />
</view>
<view class="field editable">
<view class="label">邮箱:</view>
<input class="value" value="{{contact.email}}" disabled="{{!isEditing}}" bindinput="onEmailInput" />
</view>
<view class="field editable">
<view class="label">地址:</view>
<input class="value" value="{{contact.address}}" disabled="{{!isEditing}}" bindinput="onAddressInput" />
</view>
<view class="field editable">
<view class="label">备注:</view>
<textarea class="value" value="{{contact.note}}" disabled="{{!isEditing}}" bindinput="onNoteInput" />
</view>
</view>
<!-- 操作按钮 -->
<view class="operation-section">
<button type="primary" bindtap="onEditContact" wx:if="{{!isEditing}}">修改联系人</button>
<button type="primary" bindtap="onSaveContact" wx:if="{{isEditing}}">保存联系人</button>
<button type="warn" bindtap="onDeleteContact">删除联系人</button>
</view>
</view>
contacts
collection holds documents for each contact, with fields like _id
, _openid
(user ID), address
, avatar
, email
, name
, note
, and phone
._id
._id
.name
, phone
) before saving._openid
.Here's some important code:
<!-- index.js操作展示 -->
wx.cloud.init({
env: 'george-8gktege9596a5ba5'
});
const db = wx.cloud.database();
const contactsCollection = db.collection('contacts');
Page({
data: {
letters: "ABCDEFGHIJKLMNOPQRSTUVWXYZ#",
contact: [],
filteredContacts: [],
loc: "",
screenHeight: 0,
searchTerm: ""
},
loadContactsFromDatabase() {
let self = this;
contactsCollection.field({
name: true,
_id: true
}).get({
success: res => {
let contacts = res.data;
self.arrangeContact(contacts);
},
fail: err => {
console.error('从数据库获取联系人失败:', err);
}
});
},
arrangeContact(contacts) {
var self = this;
var contact = [];
for (var i = 0; i < self.data.letters.length; i++) {
var letter = self.data.letters[i];
var group = [];
for (var j = 0; j < contacts.length; j++) {
let contactItem = contacts[j];
let contactName = contactItem.name;
let contactLetter = /^[\u4e00-\u9fa5]+$/.test(contactName[0])
? "#"
: contactName[0].toUpperCase();
if (contactLetter === letter) {
group.push(contactItem);
}
}
contact.push({
letter: letter,
group: group
});
}
self.setData({
contact: contact,
filteredContacts: contact
});
},
onSearchInput: function (e) {
const searchTerm = e.detail.value.toLowerCase();
this.setData({
searchTerm: searchTerm
});
this.filterContacts();
},
filterContacts: function () {
const self = this;
const searchTerm = self.data.searchTerm;
if (!searchTerm) {
self.setData({
filteredContacts: self.data.contact
});
return;
}
const filteredContacts = self.data.contact.map(group => {
const filteredGroup = group.group.filter(contact =>
contact.name.toLowerCase().includes(searchTerm)
);
return {
letter: group.letter,
group: filteredGroup
};
}).filter(group => group.group.length > 0);
self.setData({
filteredContacts: filteredContacts
});
},
onLoad: function () {
this.loadContactsFromDatabase();
var screenHeight = wx.getSystemInfoSync().screenHeight;
this.setData({
screenHeight: screenHeight * 2,
});
},
onTapScroll: function (e) {
var loc = e.currentTarget.dataset.loc;
this.setData({
loc: loc
});
},
onAddContact() {
wx.navigateTo({
url: '/pages/addContact/addContact'
});
}
});
<!-- card.js操作展示 -->
wx.cloud.init({
env: 'george-8gktege9596a5ba5'
});
const db = wx.cloud.database();
const contactsCollection = db.collection('contacts');
Page({
data: {
contact: {},
contactId: "",
isEditing: false
},
onLoad: function (options) {
const self = this;
const contactId = options.id;
self.setData({ contactId: contactId });
contactsCollection.doc(contactId).get({
success: function (res) {
console.log("数据库返回的数据:", res.data);
self.setData({
contact: res.data
});
},
fail: function (err) {
console.error("数据库读取失败: ", err);
wx.showToast({
title: '获取联系人失败',
icon: 'none'
});
}
});
},
onSelectPhoto: function () {
wx.chooseImage({
count: 1,
success: res => {
const tempFilePath = res.tempFilePaths[0];
this.uploadImage(tempFilePath, 'avatar');
}
});
},
uploadImage: function (tempFilePath, type) {
const cloudPath = `${type}s/${Date.now()}-${Math.floor(Math.random() * 1000)}.png`;
wx.cloud.uploadFile({
cloudPath,
filePath: tempFilePath,
success: res => {
const fileID = res.fileID;
this.updateContactAvatar(fileID);
}
});
},
updateContactAvatar: function (fileID) {
contactsCollection.doc(this.data.contactId).update({
data: {
avatar: fileID
},
success: () => {
this.setData({
'contact.avatar': fileID
});
wx.showToast({
title: '头像已更新',
icon: 'success'
});
}
});
},
onEditContact: function () {
this.setData({
isEditing: true
});
},
onNameInput: function (e) {
this.setData({
'contact.name': e.detail.value
});
},
onPhoneInput: function (e) {
this.setData({
'contact.phone': e.detail.value
});
},
onEmailInput: function (e) {
this.setData({
'contact.email': e.detail.value
});
},
onAddressInput: function (e) {
this.setData({
'contact.address': e.detail.value
});
},
onSaveContact: function () {
const self = this;
const updatedContact = self.data.contact;
contactsCollection.doc(self.data.contactId).update({
data: {
name: updatedContact.name,
phone: updatedContact.phone,
email: updatedContact.email,
address: updatedContact.address
},
success: function () {
wx.showToast({
title: '联系人已更新',
icon: 'success'
});
self.setData({
isEditing: false
});
},
fail: function (err) {
wx.showToast({
title: '更新失败',
icon: 'none'
});
console.error("更新联系人失败: ", err);
}
});
},
onDeleteContact: function () {
const self = this;
wx.showModal({
title: '删除确认',
content: '你确定要删除这个联系人吗?',
success: function (res) {
if (res.confirm) {
contactsCollection.doc(self.data.contactId).remove({
success: function () {
wx.showToast({
title: '联系人已删除',
icon: 'success'
});
wx.redirectTo({
url: '/pages/index/index',
});
},
fail: function (err) {
wx.showToast({
title: '删除失败',
icon: 'none'
});
console.error("删除联系人失败: ", err);
}
});
}
}
});
}
});
The development of this contacts mini-program provided valuable experience in designing and implementing a front-end and back-end separated architecture. Leveraging Tencent Cloud's NoSQL database and cloud functions, the back-end ensures secure, scalable, and efficient data management. The front-end, designed for ease of use, offers users intuitive access to contact management features, including adding, editing, and deleting contacts. This project not only reinforces technical skills in WeChat mini-program development but also highlights the importance of modularity, security, and data integrity in application design.