diff --git a/.gitignore b/.gitignore index 14ea590..4196004 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ $RECYCLE.BIN/ # Node.js node_modules/ + +miniprogram_npm/ diff --git a/api.js b/api.js new file mode 100644 index 0000000..a366f38 --- /dev/null +++ b/api.js @@ -0,0 +1,216 @@ +const baseUri = "https://market-staging.huww98.cn/api"; +// const baseUri = "http://localhost:8080"; + +const ErrorCode = { + InvalidJwt: 'invalid-jwt', +} + +export class ApiError extends Error { + constructor(code, message) { + super(message); + this.code = code; + this.message = message; + } +} + +function readApiResponse(response) { + const json = response.data; + if (response.statusCode != 200) { + if (json.errorCode) { + throw new ApiError(json.errorCode, json.message); + } + throw new Error("意外的错误"); + } + return json; +} + +function buildUri(path) { + return baseUri + path; +} + +function callApi(path, init) { + let builtUri = buildUri(path); + if (init) { + let builtQuery = init.query; + if (init.query) { + delete init.query; + } + if (init.paging) { + builtQuery = { + page: init.paging.page, + size: init.paging.size || 10, + ...builtQuery + } + } + if (builtQuery) { + const params = Object.entries(builtQuery).map(([key, value]) => `${key}=${encodeURIComponent(value)}`); + builtUri += "?" + Array.prototype.join.call(params, "&"); + } + } + + return new Promise((resolve, reject) => { + wx.request({ + ...init, + url: builtUri, + success: resolve, + fail: reject + }) + }).then(readApiResponse); +} + +function callApiWithAuthorization(path, init) { + const doCallApi = (jwt) => { + const builtInit = init || {}; + builtInit.header = { + "Authorization": "Bearer " + jwt, + ...builtInit.header + } + return callApi(path, builtInit); + } + const loginAndCallApi = () => { + return login().then(() => { + doCallApi(getJwt()) + }); + } + const jwt = getJwt(); + let callApiPromise; + if(jwt) { + return doCallApi(jwt).catch(e => { + if (e.errorCode == "invalid-jwt") { + logout(); + return loginAndCallApi() + } + throw e; + }); + } else { + return loginAndCallApi(); + } +} + +function callApiWarpper(method, path, body, init) { + const builtInit = { + method, + ...init + } + if (body) { + builtInit.data = body; + } + if (builtInit && builtInit.withAuthorization) { + delete builtInit.withAuthorization; + return callApiWithAuthorization(path, builtInit); + } else { + return callApi(path, builtInit); + } +} + +function getApi(path, init) { + return callApiWarpper('GET', path, null, init); +} + +function postApi(path, body, init) { + return callApiWarpper('POST', path, body, init); +} + +function putApi(path, body, init) { + return callApiWarpper('PUT', path, body, init); +} + +const jwtStorageKey = "JWT"; +export function getJwt() { + return wx.getStorageSync(jwtStorageKey); +} + +let loginPromise = null; + +export function login() { + if (loginPromise != null) { + return loginPromise; + } + loginPromise = new Promise((resolve, reject) => { + wx.login({ + success(res) { + if (res.code) { + resolve(res.code); + } else { + reject(res); + } + }, + fail: reject + }) + }).then(code => postApi("/wechat/login", { code })) + .then(result =>{ + wx.setStorageSync(jwtStorageKey, result.jwt); + loginPromise = null; + }); + return loginPromise; +} + +export function logout() { + wx.removeStorageSync(jwtStorageKey); +} + +export function hasLogedIn() { + return getJwt() !== null; +} + +export function getAllCategories() { + return getApi("/categories"); +} + +export function getAllGoodsInCategory(categoryId, page) { + return getApi(`/categories/${categoryId}/goods`, { + paging: { page } + }); +} + +export function getGoods(goodsId) { + return getApi(`/goods/${goodsId}`); +} + +export function uploadFile(localPath) { + const uri = buildUri('/wechat/uploadfile'); + return new Promise((resolve, reject) => wx.uploadFile({ + url: uri, + filePath: localPath, + name: 'file', + success: resolve, + fail: reject + })).then(res => { + res.data = JSON.parse(res.data) + return readApiResponse(res); + }); +} + +export function createGoods(goodsDescription) { + return postApi('/goods', goodsDescription, { withAuthorization: true }); +} + +export function getAllFavorite(page) { + return getApi('/goods/favorite', { + withAuthorization: true, + paging: { page } + }); +} + +export function addToFavorite(goodsId) { + return postApi(`/goods/${goodsId}/addToFavorite`, null, { withAuthorization: true }); +} + +export function deleteFromFavorite(goodsId) { + return postApi(`/goods/${goodsId}/deleteFromFavorite`, null, { withAuthorization: true }); +} + +export function getAllMy(page) { + return getApi('/goods/my', { + withAuthorization: true, + paging: { page } + }); +} + +export function getMy(descriptionId) { + return getApi(`/goods/my/${descriptionId}`, { withAuthorization: true }); +} + +export function updateGoods(goodsId, description) { + return putApi(`/goods/${goodsId}`, description, { withAuthorization: true }); +} \ No newline at end of file diff --git a/app.js b/app.js index 68c629f..d4c5356 100644 --- a/app.js +++ b/app.js @@ -1,22 +1,10 @@ +import { login, getAllCategories } from "./api.js" + App({ globalData: { - + allCategoriesPromise: getAllCategories() }, - onLaunch: function () { - wx.login({ - success: res => { - wx.request({ - url: 'https://market-staging.huww98.cn/api/wechat/login', - method: 'POST', - data: { - code: res.code - }, - success: function (loginResult) { - console.log(loginResult.statusCode); - console.log(loginResult.data); - } - }); - } - }); + onLaunch() { + login(); } }) diff --git a/app.json b/app.json index fcad58a..6e5065a 100644 --- a/app.json +++ b/app.json @@ -1,9 +1,14 @@ { "pages": [ "pages/index/index", - "pages/list/list", + "pages/published/published", "pages/post/post", - "pages/detail/detail" + "pages/detail/detail", + "pages/i/i", + "pages/favorite/favorite", + "pages/about/about", + "pages/post/selectCategory", + "pages/post/selectArea" ], "window": { "backgroundColor": "#0071BD", @@ -19,17 +24,38 @@ "text": "主页" }, { - "pagePath": "pages/post/post", - "text": "发布" + "pagePath": "pages/i/i", + "text": "我" } ], "color": "#cccccc", "selectedColor": "#00b26a" }, "networkTimeout": { - "request": 10000, + "request": 20000, "connectSocket": 10000, - "uploadFile": 10000, + "uploadFile": 60000, "downloadFile": 10000 + }, + "usingComponents": { + "van-button": "vant-weapp/button", + "van-icon": "vant-weapp/icon", + "van-tab": "vant-weapp/tab", + "van-tabs": "vant-weapp/tabs", + "van-panel": "vant-weapp/panel", + "van-cell": "vant-weapp/cell", + "van-cell-group": "vant-weapp/cell-group", + "van-slider": "vant-weapp/slider", + "van-progress": "vant-weapp/progress", + "van-checkbox": "vant-weapp/checkbox", + "van-checkbox-group": "vant-weapp/checkbox-group", + "van-radio": "vant-weapp/radio", + "van-radio-group": "vant-weapp/radio-group", + "van-search": "vant-weapp/search", + "van-tag": "vant-weapp/tag", + "van-field": "vant-weapp/field", + "van-popup": "vant-weapp/popup", + "van-swipe-cell": "vant-weapp/swipe-cell", + "van-loading": "vant-weapp/loading" } } \ No newline at end of file diff --git a/app.wxss b/app.wxss index 0bf63b7..aca15a2 100644 --- a/app.wxss +++ b/app.wxss @@ -1,4 +1,4 @@ -@import "style/weui.wxss"; +@import "miniprogram_npm/vant-weapp/common/index.wxss"; .container { display: flex; @@ -7,6 +7,21 @@ box-sizing: border-box; } +.no-item { + height: 40vh; + width: 100%; + display: flex; + justify-content: center; + align-items: center; +} + +.no-more-item { + width: 100%; + text-align: center; + padding-top: 20px; + padding-bottom: 25px; +} + page { background-color: #f8f8f8; font-size: 16px; diff --git a/behaviors/apiCall.js b/behaviors/apiCall.js new file mode 100644 index 0000000..49de0d8 --- /dev/null +++ b/behaviors/apiCall.js @@ -0,0 +1,23 @@ +export default Behavior({ + data: { + loading: false, + loadingCount: 0 + }, + methods: { + callApi(promise) { + this.setData({ + loading: true, + loadingCount: this.data.loadingCount + 1 + }); + const exitLoading = () => { + const loadingCount = this.data.loadingCount - 1 + this.setData({ + loading: loadingCount > 0, + loadingCount + }); + } + promise.then(exitLoading, exitLoading); + return promise; + } + } +}) \ No newline at end of file diff --git a/behaviors/navigationBarLoading.js b/behaviors/navigationBarLoading.js new file mode 100644 index 0000000..587226d --- /dev/null +++ b/behaviors/navigationBarLoading.js @@ -0,0 +1,21 @@ +export default Behavior({ + observers: { + loading() { + this.syncNavigationBarLoading(); + } + }, + pageLifetimes: { + show() { + this.syncNavigationBarLoading(); + }, + }, + methods: { + syncNavigationBarLoading() { + if (this.data.loading) { + wx.showNavigationBarLoading(); + } else { + wx.hideNavigationBarLoading(); + } + } + } +}) \ No newline at end of file diff --git a/behaviors/pagedContent.js b/behaviors/pagedContent.js new file mode 100644 index 0000000..42adfa5 --- /dev/null +++ b/behaviors/pagedContent.js @@ -0,0 +1,98 @@ +import apiCall from './apiCall.js' + +const pagedContent = Behavior({ + behaviors: [apiCall], + data: { + totalPages: 0, + loadedPages: 0, + loadingNextPage: false, + isLastPage: false, + content: null + }, + lifetimes: { + attached() { + this.loadFirstPage(); + }, + }, + methods: { + /** + * @returns {Promise} + */ + doLoadPage(pageToLoad) { + throw "Must be overrided"; + }, + /** + * @private + * @param {Promise<{}>} promise - Resolve to new data to be passed to setData. + */ + _loadPage(promise) { + this.setData({ loadingNextPage: true }); + this.loadingPromise = this.callApi(promise) + .then(newData => { + newData.isLastPage = newData.loadedPages >= newData.totalPages, + newData.loadingNextPage = false; + this.setData(newData); + this.loadingPromise = null; + }, e => { + this.setData({ loadingNextPage: false }); + this.loadingPromise = null; + throw e; + }); + return this.loadingPromise; + }, + loadFirstPage() { + const loadPagePromise = this.doLoadPage(0) + .then(({ totalPages, content }) => { + const loadedPages = 1; + return { + totalPages, + loadedPages, + content + }; + }); + return this._loadPage(loadPagePromise); + }, + loadNextPage() { + if (this.data.isLastPage) { + return Promise.resolve(); + } + if (this.loadingPromise) { + return this.loadingPromise; + } + const loadPagePromise = this.doLoadPage(this.data.loadedPages) + .then(({ totalPages, content }) => { + const newData = { + totalPages, + loadedPages: this.data.loadedPages + 1, + }; + const previousLength = (this.data.content || []).length; + content.forEach((item, index) => { + newData[`content[${previousLength + index}]`] = item + }); + return newData; + }) + return this._loadPage(loadPagePromise); + }, + onReachBottom() { + this.loadNextPage(); + }, + onPullDownRefresh() { + const stopRefresh = () => { + wx.stopPullDownRefresh() + } + this.loadFirstPage().then(stopRefresh, stopRefresh); + } + } +}) + +export default pagedContent; +export const pagedContentSyncStateOnLoad = Behavior({ + behaviors: [pagedContent], + pageLifetimes: { + show() { + if (!this.data.loadingNextPage) { + wx.stopPullDownRefresh(); + } + }, + }, +}); \ No newline at end of file diff --git a/components/sellingGoods/categorySellingGoodsList.js b/components/sellingGoods/categorySellingGoodsList.js new file mode 100644 index 0000000..fbdb06a --- /dev/null +++ b/components/sellingGoods/categorySellingGoodsList.js @@ -0,0 +1,19 @@ +import { getAllGoodsInCategory } from "../../api.js"; +import pagedContent from "../../behaviors/pagedContent.js" + +Component({ + behaviors: [pagedContent], + options: { + addGlobalClass: true, + }, + properties: { + categoryId: Number + }, + data: { + }, + methods: { + doLoadPage(pageToLoad) { + return getAllGoodsInCategory(this.data.categoryId, pageToLoad); + }, + } +}) diff --git a/components/sellingGoods/categorySellingGoodsList.json b/components/sellingGoods/categorySellingGoodsList.json new file mode 100644 index 0000000..8c67165 --- /dev/null +++ b/components/sellingGoods/categorySellingGoodsList.json @@ -0,0 +1,6 @@ +{ + "component": true, + "usingComponents": { + "selling-goods": "./sellingGoods" + } +} diff --git a/components/sellingGoods/categorySellingGoodsList.wxml b/components/sellingGoods/categorySellingGoodsList.wxml new file mode 100644 index 0000000..ef3bb81 --- /dev/null +++ b/components/sellingGoods/categorySellingGoodsList.wxml @@ -0,0 +1,5 @@ + + + + +没有更多内容了 \ No newline at end of file diff --git a/components/sellingGoods/categorySellingGoodsList.wxss b/components/sellingGoods/categorySellingGoodsList.wxss new file mode 100644 index 0000000..785b565 --- /dev/null +++ b/components/sellingGoods/categorySellingGoodsList.wxss @@ -0,0 +1,4 @@ +.loading { + padding-top: 40px; + text-align: center; +} \ No newline at end of file diff --git a/components/sellingGoods/sellingGoods.js b/components/sellingGoods/sellingGoods.js new file mode 100644 index 0000000..3c88bf7 --- /dev/null +++ b/components/sellingGoods/sellingGoods.js @@ -0,0 +1,26 @@ +import { area, sellOrBuy } from "../../i18n.js"; + +Component({ + properties: { + goods: { + type: Object, + observer() { + this.setData({ + "photosInList": this.data.goods.currentDescription.photos.slice(0, 3) + }); + } + } + }, + data: { + i18n: { + area, sellOrBuy + }, + }, + methods: { + navigateToDetail({ currentTarget }) { + wx.navigateTo({ + url: `/pages/detail/detail?id=${currentTarget.dataset.goodsId}`, + }) + } + } +}) diff --git a/components/sellingGoods/sellingGoods.json b/components/sellingGoods/sellingGoods.json new file mode 100644 index 0000000..e8cfaaf --- /dev/null +++ b/components/sellingGoods/sellingGoods.json @@ -0,0 +1,4 @@ +{ + "component": true, + "usingComponents": {} +} \ No newline at end of file diff --git a/components/sellingGoods/sellingGoods.wxml b/components/sellingGoods/sellingGoods.wxml new file mode 100644 index 0000000..e016974 --- /dev/null +++ b/components/sellingGoods/sellingGoods.wxml @@ -0,0 +1,17 @@ + + [{{i18n.sellOrBuy[goods.currentDescription.active]}}] {{goods.currentDescription.title}} + + + + + {{goods.currentDescription.detail}} + + + {{goods.currentDescription.sellingPrice ? '¥' + goods.currentDescription.sellingPrice : '价格面议'}} + + + {{i18n.area[goods.currentDescription.area]}} + + 1分钟前 + + \ No newline at end of file diff --git a/components/sellingGoods/sellingGoods.wxss b/components/sellingGoods/sellingGoods.wxss new file mode 100644 index 0000000..d392098 --- /dev/null +++ b/components/sellingGoods/sellingGoods.wxss @@ -0,0 +1,40 @@ +.photo-list { + display: flex; + flex-direction: row; +} + +.photo-list image { + margin: 1px; + height: 230rpx; + width: 230rpx; +} + +.item { + padding: 0 10px; + margin: 5px 0; + background: #fff +} + +.item-footer { + display: flex; + flex-direction: row; + align-items: baseline; +} + +.price { + width: 110px; + color: #1173bc; + font-size: 1.4em; +} + +.area { + display: flex; + flex-direction: row; + align-items: center; +} + +.time { + text-align: right; + flex: auto; + color: #ccc; +} \ No newline at end of file diff --git a/i18n.js b/i18n.js new file mode 100644 index 0000000..9438eb1 --- /dev/null +++ b/i18n.js @@ -0,0 +1,9 @@ +export const area = { + north: "五山校区", + south: "大学城校区", +} + +export const sellOrBuy = { + sell: "出售", + buy: "收购", +} diff --git a/images/addPhoto.svg b/images/addPhoto.svg new file mode 100644 index 0000000..bbe8059 --- /dev/null +++ b/images/addPhoto.svg @@ -0,0 +1 @@ + diff --git a/images/psb2.jpeg b/images/psb2.jpeg new file mode 100644 index 0000000..5aa0667 Binary files /dev/null and b/images/psb2.jpeg differ diff --git a/images/s1.jpg b/images/s1.jpg new file mode 100644 index 0000000..909e646 Binary files /dev/null and b/images/s1.jpg differ diff --git a/images/upload.png b/images/upload.png deleted file mode 100644 index 2d133a3..0000000 Binary files a/images/upload.png and /dev/null differ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..9097395 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "market-miniprogram", + "version": "0.2.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "vant-weapp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/vant-weapp/-/vant-weapp-0.5.6.tgz", + "integrity": "sha512-hJyTRlc9DBqd/6mMExtKahfCPQSETiYokH/cuu2h2lGe6CVq9CiwdGHAnQqSahHIWFKKIs+V5S8IrumdJlxN2w==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..1b4692e --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "market-miniprogram", + "version": "0.2.1", + "description": "华南理工大学学生会二手交易市场微信小程序", + "repository": { + "type": "git", + "url": "git+https://github.com/SCUT-StudentUnion/Market-miniprogram.git" + }, + "author": "SCUT-StudentUnion", + "bugs": { + "url": "https://github.com/SCUT-StudentUnion/Market-miniprogram/issues" + }, + "homepage": "https://github.com/SCUT-StudentUnion/Market-miniprogram#readme", + "dependencies": { + "vant-weapp": "^0.5.6" + } +} diff --git a/pages/about/about.js b/pages/about/about.js new file mode 100644 index 0000000..0520273 --- /dev/null +++ b/pages/about/about.js @@ -0,0 +1,2 @@ +Page({ +}) \ No newline at end of file diff --git a/pages/list/list.json b/pages/about/about.json similarity index 100% rename from pages/list/list.json rename to pages/about/about.json diff --git a/pages/about/about.wxml b/pages/about/about.wxml new file mode 100644 index 0000000..44cbfa7 --- /dev/null +++ b/pages/about/about.wxml @@ -0,0 +1,7 @@ + +华工集市 +Copyright© 华南理工大学学生会版权所有 +如有任何建议 +欢迎在华南理工大学学生会微信公众号后台留言反馈 +让我们共同建设更好的华工集市平台 + \ No newline at end of file diff --git a/pages/about/about.wxss b/pages/about/about.wxss new file mode 100644 index 0000000..9e52ddb --- /dev/null +++ b/pages/about/about.wxss @@ -0,0 +1,9 @@ +text { + height: 80vh; + display: flex; + flex-direction: column; + justify-content: center; + text-align:center; + color:#6e6e6e; + font-size:0.8em +} \ No newline at end of file diff --git a/pages/detail/detail.js b/pages/detail/detail.js index 501a7a1..da6a79b 100644 --- a/pages/detail/detail.js +++ b/pages/detail/detail.js @@ -1,67 +1,45 @@ +import { + getGoods +} from "../../api.js"; +import { area, sellOrBuy } from "../../i18n.js"; Page({ - - /** - * 页面的初始数据 - */ data: { - text: "" - }, - - /** - * 生命周期函数--监听页面加载 - */ - onLoad: function (options) { + text: 2, + detail: { + isCollected: "已收藏", + title: "网球拍大甩卖", + description: '11成新网球拍hahahahah哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈', + OldPrice: "¥666", + NewPrice: "¥233", + userid: "wxid_abcdefg", + contact: "23333", + place: "五山" + }, + carousel: [ + ] + }, + onLoad: function(options) { this.setData({ text: options.id }) + getGoods(this.data.text).then(( + res + ) => { + console.log(res) + let desc = res.currentDescription; + this.setData({ + 'detail.title': desc.title, + 'detail.description': desc.detail, + 'detail.place': (() => { + return area[desc.area] + + })(), + 'detail.contact': `联系方式: ${ desc.contactInfo }`, + 'detail.NewPrice': desc.sellingPrice, + 'detail.userid': `用户id:${res.releasedBy.id}`, + 'carousel':desc.photos + + }) + }) }, - - /** - * 生命周期函数--监听页面初次渲染完成 - */ - onReady: function () { - - }, - - /** - * 生命周期函数--监听页面显示 - */ - onShow: function () { - - }, - - /** - * 生命周期函数--监听页面隐藏 - */ - onHide: function () { - - }, - - /** - * 生命周期函数--监听页面卸载 - */ - onUnload: function () { - - }, - - /** - * 页面相关事件处理函数--监听用户下拉动作 - */ - onPullDownRefresh: function () { - - }, - - /** - * 页面上拉触底事件的处理函数 - */ - onReachBottom: function () { - - }, - - /** - * 用户点击右上角分享 - */ - onShareAppMessage: function () { - - } -}) +}) \ No newline at end of file diff --git a/pages/detail/detail.wxml b/pages/detail/detail.wxml index a71c57e..241c62b 100644 --- a/pages/detail/detail.wxml +++ b/pages/detail/detail.wxml @@ -1 +1,69 @@ -{{text}} \ No newline at end of file + + + + + + + + + + + + + + + + + 出售 + {{ detail.title }} + + + + + + + {{detail.NewPrice}} + + + {{detail.place}} + + 1分钟前 + + + + + + {{detail.description}} + + + + + + {{detail.userid}} + + {{detail.contact}} + + + 复制 + + + + + + + + + + + + + + + + + + + 已售出此商品 + 分享 + + \ No newline at end of file diff --git a/pages/detail/detail.wxss b/pages/detail/detail.wxss index 4c8cd74..125ed25 100644 --- a/pages/detail/detail.wxss +++ b/pages/detail/detail.wxss @@ -1 +1,140 @@ /* pages/detail/detail.wxss */ + +.mycontainer { + display: flex; + background: white; + justify-content: flex-start; +} + +.badge { + background: #1073ba; + border-radius: 15rpx; + color: white; + font-size: 22rpx; + padding: 10rpx; + margin-right: 10rpx; +} + +.title{ + font-size:28rpx; + font-weight: bold; +} + +.inline{ + display:inline-block;float:left; +} + +.btn{ + background:#1173bc!important; + color: white!important; +} + +.weui-form-preview_modified { + position: relative; + background-color: #fff; +} + +.weui-form-preview_modified:before { + top: 0; + border-top: 0rpx solid #d9d9d9; +} + +.weui-form-preview_modified:after, .weui-form-preview_modified:before { + content: " "; + position: absolute; + left: 0; + right: 0; + height: 0px; + color: #d9d9d9; +} + + +.weui-form-preview__hd { + position: relative; + padding: 10px 15px; + text-align: right; + line-height: 2.5em; +} + +.weui-form-preview__hd:after { + content: " "; + position: absolute; + left: 0; + bottom: 0; + right: 0; + height: 1px; + border-bottom: 0rpx solid #d9d9d9; + color: #d9d9d9; + left: 15px; +} + +.weui-form-preview__ft { + position: relative; + line-height: 50px; + display: -webkit-box; + display: -webkit-flex; + display: flex; +} + +.weui-form-preview__ft:after { + content: " "; + position: absolute; + left: 0; + top: 0; + right: 0; + height: 0px; + border-top: 0rpx solid #d5d5d6; + color: #d5d5d6; +} + +.weui-form-preview__value { + display: block; + overflow: hidden; + word-break: normal; + word-wrap: break-word; + color: black; + +} + +.weui-form-preview__value { + font-size: 14px; + flex-basis: 80%; + text-align: start; + text-align-last: start; +} + +.weui-form-preview__value_in-hd { + font-size: 26px; +} + +.weui-form-preview__item { + overflow: hidden; +} + +.weui-form-preview__label { + float: left; + margin-right: 1em; + min-width: 4em; + color: #999; + text-align: start; + text-align-last: start; + flex-basis:20%; + flex-grow: 1 +} + +.van-panel { + background: #fff; +} + +.van-panel__header-value { + color: #1173bc; + font-weight:normal; +} + +.van-panel__footer { + padding: 10px 15px; +} + +.van-panel__footer2 { + padding: 3px 15px; +} diff --git a/pages/favorite/favorite.js b/pages/favorite/favorite.js new file mode 100644 index 0000000..431ea26 --- /dev/null +++ b/pages/favorite/favorite.js @@ -0,0 +1,26 @@ +import { getAllFavorite, deleteFromFavorite } from "../../api.js"; +import { pagedContentSyncStateOnLoad } from "../../behaviors/pagedContent.js" +import navigationBarLoading from "../../behaviors/navigationBarLoading.js" + +Component({ + behaviors: [pagedContentSyncStateOnLoad, navigationBarLoading], + data: { + }, + methods: { + doLoadPage(pageToLoad) { + return getAllFavorite(pageToLoad); + }, + delete({ currentTarget }) { + const goodsId = currentTarget.dataset.goodsId; + this.setData({ + content: this.data.content.filter(f => f.goods.id != goodsId) + }); + this.callApi(deleteFromFavorite(goodsId)).catch(e => { + wx.showToast({ + title: '删除失败:' + e, + icon: 'none' + }) + }); + } + }, +}) \ No newline at end of file diff --git a/pages/favorite/favorite.json b/pages/favorite/favorite.json new file mode 100644 index 0000000..48769d2 --- /dev/null +++ b/pages/favorite/favorite.json @@ -0,0 +1,7 @@ +{ + "usingComponents": { + "selling-goods": "/components/sellingGoods/sellingGoods" + }, + "navigationBarTitleText": "我的收藏", + "enablePullDownRefresh": true +} \ No newline at end of file diff --git a/pages/favorite/favorite.wxml b/pages/favorite/favorite.wxml new file mode 100644 index 0000000..cfb1b43 --- /dev/null +++ b/pages/favorite/favorite.wxml @@ -0,0 +1,9 @@ + + + 删除 + + + +你还没有收藏 + +没有更多收藏了 \ No newline at end of file diff --git a/pages/favorite/favorite.wxss b/pages/favorite/favorite.wxss new file mode 100644 index 0000000..c68164d --- /dev/null +++ b/pages/favorite/favorite.wxss @@ -0,0 +1,8 @@ +.delete-btn { + width: 65px; + height: 100%; + background: red; + display: flex; + justify-content: center; + align-items: center; +} diff --git a/pages/i/i.js b/pages/i/i.js new file mode 100644 index 0000000..72b5fe5 --- /dev/null +++ b/pages/i/i.js @@ -0,0 +1,5 @@ +Page({ + data: { + + }, +}) \ No newline at end of file diff --git a/pages/i/i.json b/pages/i/i.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/pages/i/i.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/pages/i/i.wxml b/pages/i/i.wxml new file mode 100644 index 0000000..71b7877 --- /dev/null +++ b/pages/i/i.wxml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pages/i/i.wxss b/pages/i/i.wxss new file mode 100644 index 0000000..237d673 --- /dev/null +++ b/pages/i/i.wxss @@ -0,0 +1,24 @@ +.header { + height: 300rpx; + background:#0071bd; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.header .avatar { + width: 160rpx; + height: 160rpx; + border-radius: 50%; + display: block; + overflow: hidden; +} + +.header .nick-name { + color: white; +} + +.cell-group { + margin-bottom: 20px; +} \ No newline at end of file diff --git a/pages/index/index.js b/pages/index/index.js index b5a39c1..d947f6d 100644 --- a/pages/index/index.js +++ b/pages/index/index.js @@ -1,42 +1,60 @@ -const app = getApp() +const app = getApp(); -Page({ +Component({ data: { - avatarUrl: './user-unlogin.png', - userInfo: {}, - logged: false, - takeSession: false, - requestResult: '' + active: 0, + carousel: [{ + id: 0, + img: '/images/s1.jpg', + url: '/pages/detail/detail' + }, + { + id: 1, + img: '/images/psb2.jpeg', + url: '/pages/detail/detail' + } + ], }, - - onLoad: function () { - - // 获取用户信息 - wx.getSetting({ - success: res => { - if (res.authSetting['scope.userInfo']) { - // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框 - wx.getUserInfo({ - success: res => { - this.setData({ - avatarUrl: res.userInfo.avatarUrl, - userInfo: res.userInfo - }) - } - }) - } + lifetimes: { + attached() { + app.globalData.allCategoriesPromise + .then(categories => { + this.setData({ categories }) + }); + this.loadList(0); + }, + }, + pageLifetimes: { + show() { + const lists = this.selectAllComponents(".list"); + if (lists.every(l => !l.data.loadingNextPage)) { + wx.stopPullDownRefresh(); } - }) + }, }, - - onGetUserInfo: function (e) { - if (!this.logged && e.detail.userInfo) { + methods: { + activeList() { + return this.selectComponent(`#list-${this.data.active}`); + }, + onPullDownRefresh() { + // Unload all lists but active one. + this.setData({ + listLoaded: [], + [`listLoaded[${this.data.active}]`]: true + }); + this.activeList().onPullDownRefresh(); + }, + onReachBottom() { + this.activeList().onReachBottom(); + }, + loadList(index) { this.setData({ - logged: true, - avatarUrl: e.detail.userInfo.avatarUrl, - userInfo: e.detail.userInfo - }) - } - }, - -}) + active: index, + [`listLoaded[${index}]`]: true + }); + }, + tabChange({ detail: {index} }) { + this.loadList(index); + }, + } +}) \ No newline at end of file diff --git a/pages/index/index.json b/pages/index/index.json index 9e26dfe..06cc8f3 100644 --- a/pages/index/index.json +++ b/pages/index/index.json @@ -1 +1,6 @@ -{} \ No newline at end of file +{ + "usingComponents": { + "selling-goods-list": "/components/sellingGoods/categorySellingGoodsList" + }, + "enablePullDownRefresh": true +} \ No newline at end of file diff --git a/pages/index/index.wxml b/pages/index/index.wxml index 5faa3b6..4b28596 100644 --- a/pages/index/index.wxml +++ b/pages/index/index.wxml @@ -1,21 +1,17 @@ - + + 搜索 + - - - 发布二手信息 - - + + + + + - - - 商品列表 - - - - - - Homepage is building... - - - - \ No newline at end of file + + + + + + + diff --git a/pages/index/index.wxss b/pages/index/index.wxss index 446a469..348f3c5 100644 --- a/pages/index/index.wxss +++ b/pages/index/index.wxss @@ -1,61 +1,3 @@ -/**index.wxss**/ - -page { - background: #f6f6f6; - display: flex; - flex-direction: column; - justify-content: flex-start; -} - -.userinfo, .uploader { - margin-top: 40rpx; - height: 140rpx; - width: 100%; - background: #fff; - border: 1px solid rgba(0, 0, 0, 0.1); - border-left: none; - border-right: none; - display: flex; - flex-direction: row; - align-items: center; - transition: all 300ms ease; -} - -.userinfo-avatar { - width: 100rpx; - height: 100rpx; - margin: 20rpx; - border-radius: 50%; - background-size: cover; - background-color: white; -} - -.userinfo-avatar:after { - border: none; -} - -.userinfo-nickname { - font-size: 32rpx; - color: #007aff; - background-color: white; - background-size: cover; -} - -.userinfo-nickname::after { - border: none; -} - -.uploader { - height: auto; - padding: 0 0 0 0rpx; - flex-direction: column; - align-items: flex-start; - box-sizing: border-box; -} - -.uploader-text { - width: 100%; - line-height: 52px; - font-size: 34rpx; - color: #007aff; -} +.content { + min-height: 100vh; +} \ No newline at end of file diff --git a/pages/index/user-unlogin.png b/pages/index/user-unlogin.png deleted file mode 100644 index 95b27e4..0000000 Binary files a/pages/index/user-unlogin.png and /dev/null differ diff --git a/pages/list/list.js b/pages/list/list.js deleted file mode 100644 index 878d8de..0000000 --- a/pages/list/list.js +++ /dev/null @@ -1,78 +0,0 @@ -Page({ - data: { - goods_list: [{ - id:1, - title: "小风车", - description: "转呀转呀转", - pic: "/images/upload.png" - }, { - id:2, - title: "大蟑螂", - description: "交通工具", - pic: "/images/upload.png" - }, - { - id:3, - title: "二手书", - description: "流通的二手书", - pic: "/images/upload.png" - } - ] - }, - - /** - * 生命周期函数--监听页面加载 - */ - onLoad: function(options) { - - }, - - /** - * 生命周期函数--监听页面初次渲染完成 - */ - onReady: function() { - - }, - - /** - * 生命周期函数--监听页面显示 - */ - onShow: function() { - - }, - - /** - * 生命周期函数--监听页面隐藏 - */ - onHide: function() { - - }, - - /** - * 生命周期函数--监听页面卸载 - */ - onUnload: function() { - - }, - - /** - * 页面相关事件处理函数--监听用户下拉动作 - */ - onPullDownRefresh: function() { - - }, - - /** - * 页面上拉触底事件的处理函数 - */ - onReachBottom: function() { - - }, - - /** - * 用户点击右上角分享 - */ - onShareAppMessage: function() { - - } -}) \ No newline at end of file diff --git a/pages/list/list.wxml b/pages/list/list.wxml deleted file mode 100644 index 1b43a27..0000000 --- a/pages/list/list.wxml +++ /dev/null @@ -1,15 +0,0 @@ - - 商品列表 - - - - - - - {{item.title}} - {{item.description}} - - - - - \ No newline at end of file diff --git a/pages/list/list.wxss b/pages/list/list.wxss deleted file mode 100644 index 601ce69..0000000 --- a/pages/list/list.wxss +++ /dev/null @@ -1 +0,0 @@ -/* pages/list/list.wxss */ \ No newline at end of file diff --git a/pages/post/post.js b/pages/post/post.js index d379282..f0f6455 100644 --- a/pages/post/post.js +++ b/pages/post/post.js @@ -1,74 +1,149 @@ -Page({ +import { area, sellOrBuy } from "../../i18n.js"; +import { uploadFile, createGoods, updateGoods, getMy } from "../../api.js" +import apiCall from '../../behaviors/apiCall.js' +import navigationBarLoading from "../../behaviors/navigationBarLoading.js" + +const descriptionDefaults = { + active: 'sell' +}; + +Component({ + behaviors: [apiCall, navigationBarLoading], + properties: { + descriptionId: Number + }, data: { - text: "data", - types: [{ - name: "电子产品", - isSelected: true - }, { - name: "生活用具", - isSelected: false - }, { - name: "书籍教材", - isSelected: false - }], - img: [], - detail: '', - contact: '', - bought: '', - sell: '', - category: 'electric', - index: '', - isAgree: '' + maxPhotoCount: 9, + localPhotos: [], + i18n: { + area, + sellOrBuy, + }, + description: { + ...descriptionDefaults + }, + sellOrBuy: Object.keys(sellOrBuy), + area: Object.keys(area) }, - onLoad: function() {}, - upimg: function() { - var mythis = this; - wx.chooseImage({ - count: 9, - sizeType: ['original', 'compressed'], - sourceType: ['album', 'camera'], - success(res) { - // tempFilePath可以作为img标签的src属性显示图片 - mythis.setData({ - img: res.tempFilePaths - }); + lifetimes: { + attached() { + if (this.data.descriptionId) { + this.callApi(getMy(this.data.descriptionId)).then(({ goods, photos, ...description }) => { + this.setData({ + description, + goods, + localPhotos: photos.map(p => ({ path: p.url, remoteId: p.id })) + }); + }) } - }); + }, }, - askdel: function() { - var mythis = this; - wx.showModal({ - title: 'info', - content: 'del?', - success(res) { - if (res.confirm == true) { - mythis.setData({ - img: [] + methods: { + selectCategory() { + wx.navigateTo({ + url: 'selectCategory', + }); + }, + selectArea() { + wx.navigateTo({ + url: 'selectArea', + }); + }, + onSelectImage() { + wx.chooseImage({ + count: this.data.maxPhotoCount - this.data.localPhotos.length, + success: res => { + const newPhotos = res.tempFilePaths.map(path => ({ path })); + this.setData({ + localPhotos: this.data.localPhotos.concat(newPhotos) }); } + }); + }, + onDeleteImage({ currentTarget }) { + const photo = currentTarget.dataset.photo; + wx.showModal({ + title: '要删除该图片吗?', + success: res => { + if (res.confirm) { + this.setData({ + localPhotos: this.data.localPhotos.filter(p => p.path != photo.path) + }); + } + } + }); + }, + onFieldChange({ currentTarget, detail }) { + const fieldName = `description.${currentTarget.dataset.fieldName}`; + this.setData({ + [fieldName]: detail + }); + }, + onSubmit(e) { + const value = e.detail.value; + for (const k of Object.keys(sellOrBuy)) { + delete value[k]; } - }); - }, - tapcat: function(e) { - for (var j = 0; j < this.data.types.length; j++) { - this.data.types[j].isSelected = false; - } - var index = e.target.dataset.in; - this.data.types[index].isSelected = true; - this.setData({ - types: this.data.types, - index: index - }); - }, - bindAgreeChange: function(e) { - if (this.data.isAgree) { this.setData({ - isAgree: "" //checkbox[0]='agree'或者empty + description: { + ...this.data.description, + ...value, + weChatFormId: e.detail.formId + } }) - } else { - this.setData({ - isAgree: "ture" //checkbox[0]='agree'或者empty + + let uploadedCount = 0; + const updateLoading = () => { + wx.showLoading({ + title: `上传图片(${uploadedCount}/${this.data.localPhotos.length})`, + mask: true + }); + } + updateLoading(); + let uploadPromise = Promise.resolve(); + for (const localPhoto of this.data.localPhotos) { + if (localPhoto.remoteId) { + // already uploaded + uploadedCount++; + updateLoading(); + continue; + } + uploadPromise = uploadPromise + .then(() => uploadFile(localPhoto.path)) + .then(res => { + localPhoto.remoteId = res.photoId; + uploadedCount++; + updateLoading(); + }); + } + const submitPromise = uploadPromise.then(() => { + this.setData({ + 'description.photos': this.data.localPhotos.map(p => ({ id: p.remoteId })) + }); + if (this.data.goods) { + return updateGoods(this.data.goods.id, this.data.description); + } else { + return createGoods(this.data.description); + } }) + + this.callApi(submitPromise).then(() => { + wx.hideLoading(); + wx.showModal({ + title: '提交成功', + content: '校会工作人员将为您尽快审核', + showCancel: false, + success() { + wx.navigateBack(); + } + }) + }).catch(e => { + wx.hideLoading(); + wx.showToast({ + title: '发布失败:' + e, + icon: 'none' + }) + }); } } }) diff --git a/pages/post/post.json b/pages/post/post.json index 9e26dfe..5d2119e 100644 --- a/pages/post/post.json +++ b/pages/post/post.json @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "navigationBarTitleText": "商品发布" +} \ No newline at end of file diff --git a/pages/post/post.wxml b/pages/post/post.wxml index e35bfdb..a8e38eb 100644 --- a/pages/post/post.wxml +++ b/pages/post/post.wxml @@ -1,57 +1,39 @@ - - 请选择分类\n右滑获取更多 - - {{item.name}} - - +
+ + + + + {{i18n.sellOrBuy[item]}} + + + - - - -