前言
公司業(yè)務(wù)需要,PC端,移動(dòng)端都用到了第三方 網(wǎng)易云信 IM 來實(shí)現(xiàn)在線客服咨詢侧漓。
在這當(dāng)中難免遇到一些需求是網(wǎng)易云信沒有提供缺前,需要自行編碼進(jìn)行擴(kuò)展的蛀醉。寫此篇文章的目的正是因業(yè)務(wù)需要,需要在網(wǎng)易云信的基礎(chǔ)上進(jìn)行消息類型的擴(kuò)展衅码。
此篇文章里的代碼是基于 網(wǎng)易云信 NIM_Android_Demo_v4.5.1 版 進(jìn)行修改的
如下圖所示的消息類型
標(biāo)題是Android版逝段,可想而知垛玻,肯定還有其他如 iOS版,Web版等奶躯,不可能此類型的消息(我稱它為圖文消息
)只支持android帚桩,而在iOS或Web端無法顯示問題。以下附上其他版本擴(kuò)展的鏈接
正文
使用 android studio 打開項(xiàng)目運(yùn)行試試嘹黔,確保項(xiàng)目運(yùn)行沒有問題账嚎。
-
運(yùn)行沒有問題后,修改以下幾個(gè)文件配置,將demo修改為自己所用郭蕉。
修改
NimApplication.java
中onCreate
函數(shù)中的以下幾行參數(shù)疼邀,以下幾行參數(shù)用于android平臺一些機(jī)型消息推送問題。
@Override
public void onCreate() {
super.onCreate();
DemoCache.setContext(this);
// 注冊小米推送召锈,參數(shù):小米推送證書名稱(需要在云信管理后臺配置)旁振、appID 、appKey涨岁,該邏輯放在 NIMClient init 之前
NIMPushClient.registerMiPush(this, "證書名", "appID", "appKey");
// 注冊華為推送规求,參數(shù):華為推送證書名稱(需要在云信管理后臺配置)
NIMPushClient.registerHWPush(this, "證書名");
// ...
}
登錄網(wǎng)易云信后臺,應(yīng)用 -> [你的應(yīng)用] -> 證書管理 卵惦,在此添加你的證書后阻肿,然后將證書名,appID 沮尿、appKey 填寫到上面代碼中丛塌。
以上三個(gè)步驟是通用的,將云信demo工程改為自己所用必須要做的修改畜疾。接下來就是添加代碼赴邻,增加自定義圖文鏈接消息功能了。
- 這個(gè)功能主要用于我們給網(wǎng)站用戶發(fā)送促銷或活動(dòng)等使用啡捶,圖文鏈接消息的發(fā)送功能不開放給用戶姥敛。下圖給出示例圖,當(dāng)用戶點(diǎn)擊咨詢時(shí)瞎暑,我們自動(dòng)給他回復(fù)一條圖文鏈接消息彤敛。
此處有些讀者可能會想了赌,這有什么難的墨榄,不就是個(gè)網(wǎng)頁嘛。后臺自動(dòng)回復(fù)消息時(shí)發(fā)送一段如下的html代碼勿她,然后設(shè)置下樣式排版一下就行了袄秩。
<a href="#" style="樣式省略了"> <div>頭部標(biāo)題</div> <img src="圖片" /> <div>底部描述</div> </a>
這樣一來就有個(gè)問題,消息顯示面板支持發(fā)送html代碼了逢并。其他懂行行家要是發(fā)送如下的代碼就慘了之剧。
應(yīng)該沒人會這么傻吧,自己坑害自己砍聊。當(dāng)然我們使用js的escape
和unescape
在消息的收發(fā)的時(shí)候轉(zhuǎn)化下就好了背稼。
但是此時(shí)我們要是在app里看這個(gè)消息
看到的卻是網(wǎng)頁代碼辩恼,要是在PC客戶端看這條消息肯定也是這樣雇庙。當(dāng)然我們可以針對不平終端使用正則或者模版匹配然后使其顯示成我們想要的樣子谓形,如此一來,又有個(gè)問題疆前,消息推送內(nèi)容的顯示寒跳。如下圖
還有其它問題我就不一一列出了竹椒,你會發(fā)現(xiàn)自己在這條不歸路上越陷越深童太,做各種兼容,哪天產(chǎn)品需求一變你就痛苦去吧胸完。(我為什么花一個(gè)篇幅來說這個(gè)問題书释。1.這種解決問題的方式是在給自己挖坑。2.作為一個(gè)開發(fā)工程師第一時(shí)間應(yīng)該想到的是擴(kuò)展赊窥。3.我們目前就是這種做法爆惧,我看著是著實(shí)的難受。)在demo的uikit模塊下就有自定義消息的文檔說明
- 依照文檔擴(kuò)展新增自定義消息
在接口CustomAttachmentType.java
中新增一個(gè)圖文類型LINK
public interface CustomAttachmentType { // 多端統(tǒng)一 int Guess = 1; int SnapChat = 2; int Sticker = 3; int RTS = 4; // 新增圖文鏈接消息 int LINK = 5; }
在包
com.netease.nim.demo.session.extension
目錄下創(chuàng)建圖文鏈接消息對象LinkAttachment.java
// 此處忽略import包 public class LinkAttachment extends CustomAttachment { private final String KEY_TITLE = "title"; private final String KEY_DESCRIBE = "describe"; private final String KEY_IMAGE_URL = "image_url"; private final String KEY_LINK_URL = "link_url"; // 圖文消息的標(biāo)題锨能,必須有 private String title; // 圖文消息的描述扯再,可以為空 private String describe; // 點(diǎn)擊圖文消息跳轉(zhuǎn)的鏈接地址,必須有 private String linkUrl; // 圖文消息的圖片 private String imageUrl; public LinkAttachment() { super(CustomAttachmentType.LINK); } public String getTitle() { return title; } public String getDescribe() { return describe; } public String getLinkUrl() { return linkUrl; } public String getImageUrl() { return imageUrl; } public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; } public void setTitle(String title) { this.title = title; } public void setDescribe(String describe) { this.describe = describe; } public void setLinkUrl(String linkUrl) { this.linkUrl = linkUrl; } // 解析數(shù)據(jù)內(nèi)容 @Override protected void parseData(JSONObject data) { title = data.getString(KEY_TITLE); describe = data.getString(KEY_DESCRIBE); linkUrl = data.getString(KEY_LINK_URL); imageUrl = data.getString(KEY_IMAGE_URL); } // 數(shù)據(jù)打包 @Override protected JSONObject packData() { JSONObject data = new JSONObject(); data.put(KEY_TITLE, getTitle()); data.put(KEY_DESCRIBE, getDescribe()); data.put(KEY_IMAGE_URL, getImageUrl()); data.put(KEY_LINK_URL, getLinkUrl()); return data; } }
在
res/layout
目錄下創(chuàng)建圖文消息的顯示的布局文件link_image.xml
址遇,用來顯示我們自定義的消息如何展現(xiàn)熄阻。<?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android"> <LinearLayout android:layout_width="220dp" android:layout_height="wrap_content" android:background="@color/transparent" android:orientation="vertical" android:padding="10dp"> <!-- 圖文消息的標(biāo)題 --> <TextView android:id="@+id/title" android:layout_width="match_parent" android:layout_height="40dp" android:adjustViewBounds="true" android:gravity="center_vertical" android:maxLines="2" android:textSize="16sp" android:textColor="@color/color_blue_0888ff" android:textStyle="bold" /> <!-- 圖文消息中的圖片,設(shè)置個(gè)默認(rèn)圖片 --> <ImageView android:id="@+id/link_image" android:layout_width="match_parent" android:layout_height="120dp" android:layout_gravity="center_vertical" android:adjustViewBounds="true" android:src="@drawable/default_image" android:background="@drawable/image_border" /> <!-- 圖文消息中的描述 --> <TextView android:id="@+id/describe" android:layout_width="match_parent" android:layout_height="60dp" android:adjustViewBounds="true" android:lineSpacingExtra="2dp" android:maxLines="3" android:paddingTop="5dp" android:textColor="@color/color_blue_3a9efb" android:textSize="14sp" /> </LinearLayout> </merge>
上面文件中用了
@drawable/image_border
倔约,用來顯示圖片上下邊框的秃殉,非必須。
demo/res/drawable/image_border.xml
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape> <solid android:color="@color/split_line_grey_color_d9d9d9" /> </shape> </item> <item android:bottom="1px" android:top="1px"> <shape> <solid android:color="@color/white" /> </shape> </item> </layer-list>
接著創(chuàng)建圖文消息的顯示類
MsgViewHolderLink.java
浸剩,用來處理我們自定義的消息根據(jù)業(yè)務(wù)如何展現(xiàn)钾军。public class MsgViewHolderLink extends MsgViewHolderBase { private LinkAttachment attachment; // 圖片 private ImageView imageView; // 標(biāo)題 private TextView titleView; // 描述 private TextView describeView; public MsgViewHolderLink(BaseMultiItemFetchLoadAdapter adapter) { super(adapter); } @Override protected int getContentResId() { // 布局文件使用上面創(chuàng)建的文件 return R.layout.link_image; } @Override protected void inflateContentView() { imageView = (ImageView) view.findViewById(R.id.link_image); titleView = (TextView) view.findViewById(R.id.title); describeView = (TextView) view.findViewById(R.id.describe); } // 此條消息點(diǎn)擊時(shí)響應(yīng)事件 @Override protected void onItemClick() { // app內(nèi)打開瀏覽器,將網(wǎng)頁URL傳入,此處有誤先別著急乒省,往下看文檔或者先注釋 WebViewActivity.startActivity(context, attachment.getTitle(), attachment.getLinkUrl()); } @Override protected void bindContentView() { attachment = (LinkAttachment) message.getAttachment(); // MsgDirectionEnum.Out 表示發(fā)出去的消息巧颈, In 標(biāo)示收到的消息 // 設(shè)置發(fā)送的消息和收到的消息文本顏色 if (message.getDirect() == MsgDirectionEnum.Out) { int color = DemoCache.getContext().getResources().getColor(R.color.white); titleView.setTextColor(color); describeView.setTextColor(color); } else if (message.getDirect() == MsgDirectionEnum.In) { int titleColor = DemoCache.getContext().getResources().getColor(R.color.color_blue_0888ff); int describeColor = DemoCache.getContext().getResources().getColor(R.color.color_blue_3a9efb); titleView.setTextColor(titleColor); describeView.setTextColor(describeColor); } titleView.setText(attachment.getTitle()); // 判斷是否傳了圖片,如果沒有傳圖片袖扛,則不顯示圖片區(qū)域 if (TextUtils.isEmpty(attachment.getImageUrl())) { imageView.setVisibility(View.GONE); } else { imageView.setVisibility(View.VISIBLE); // 圖片加載器,異步加載網(wǎng)絡(luò)圖片十籍,此處有誤先別著急蛆封,往下看文檔或者先注釋掉此處 ImageLoader.onLoadImage(attachment.getImageUrl(), new ImageLoader.LoadImageListener() { @Override public void onLoadImage(Bitmap bitmap, String bitmapPath) { if (bitmap != null) { imageView.setImageBitmap(bitmap); } } }); } // 判斷是否傳了描述,如果沒有描述勾栗,則不顯示描述區(qū)域 if (TextUtils.isEmpty(attachment.getDescribe())) { describeView.setVisibility(View.GONE); } else { describeView.setText(attachment.getDescribe()); describeView.setVisibility(View.VISIBLE); } } }
接下再創(chuàng)建上面用到的
WebViewActivity.java
和布局文件webview_activity.xml
惨篱,用于顯示點(diǎn)擊消息時(shí)app內(nèi)跳轉(zhuǎn)頁面顯示網(wǎng)頁。
demo/res/layout/webview_activity.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/color_background"> <android.support.design.widget.AppBarLayout android:id="@+id/app_bar_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay" app:elevation="0dp"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:titleTextAppearance="@style/Toolbar.TitleText"></android.support.v7.widget.Toolbar> </android.support.design.widget.AppBarLayout> <ProgressBar android:id="@+id/web_loading_progress" android:layout_width="60dp" android:layout_height="match_parent" android:layout_below="@id/app_bar_layout" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:elevation="1dp" android:max="100" android:min="0" android:visibility="gone" /> <WebView android:id="@+id/webView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/app_bar_layout"></WebView> </RelativeLayout>
com.netease.nim.demo.session.activity.WebViewActivity.java
// 此處忽略import包 //app內(nèi)嵌網(wǎng)頁支持 public class WebViewActivity extends UI { private final static String EXTRA_TITLE = "EXTRA_TITLE"; private final static String EXTRA_LINK_URL = "EXTRA_LINK_URL"; // 顯示網(wǎng)頁 private WebView webView; // 加載進(jìn)度狀態(tài) private ProgressBar progress; public static void startActivity(Context context, String title, String url) { Intent intent = new Intent(); intent.setClass(context, WebViewActivity.class); intent.putExtra(EXTRA_LINK_URL, url); intent.putExtra(EXTRA_TITLE, title); context.startActivity(intent); } @Override protected void onCreate(Bundle saveInstanceState) { super.onCreate(saveInstanceState); setContentView(R.layout.webview_activity); ToolBarOptions options = new NimToolBarOptions(); options.titleString = getIntent().getStringExtra(EXTRA_TITLE); options.logoId = 0; setToolBar(R.id.toolbar, options); findViews(); initViewData(); } private void findViews() { webView = findViewById(R.id.webView); progress = findViewById(R.id.web_loading_progress); } private void initViewData() { // 加載傳入過來的鏈接地址 webView.loadUrl(getIntent().getStringExtra(EXTRA_LINK_URL)); // 重寫WebViewClient的shouldOverrideUrlLoading方法围俘,實(shí)現(xiàn)在webview內(nèi)加載網(wǎng)頁 WebViewClient webViewClient = new WebViewClient() { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { progress.setVisibility(View.VISIBLE); progress.setProgress(0); super.onPageStarted(view, url, favicon); } @Override public void onPageFinished(WebView view, String url) { progress.setVisibility(View.GONE); super.onPageFinished(view, url); } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } }; WebChromeClient chromeClient = new WebChromeClient() { // 頁面加載進(jìn)度改變時(shí)候的回調(diào) @Override public void onProgressChanged(WebView view, int newProgress) { progress.setProgress(ScreenUtil.screenWidth * (newProgress / 100)); super.onProgressChanged(view, newProgress); } }; webView.setWebViewClient(webViewClient); webView.setWebChromeClient(chromeClient); // 獲取 WebSettings 對象 WebSettings settings = webView.getSettings(); // 設(shè)置支持js settings.setJavaScriptEnabled(true); settings.setDefaultTextEncodingName("UTF-8"); // 設(shè)置緩存使用方式為優(yōu)先加載本地緩存 settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //設(shè)置開啟數(shù)據(jù)庫存儲API權(quán)限 settings.setDatabaseEnabled(true); // 開啟DOM存儲API功能 settings.setDomStorageEnabled(true); // 設(shè)置是否開啟定位功能 settings.setGeolocationEnabled(true); // 構(gòu)造緩存路徑 String cacheDirPath = getFilesDir().getAbsolutePath() + "/webcache/"; // 設(shè)置保存地理信息數(shù)據(jù)路徑 settings.setGeolocationDatabasePath(cacheDirPath); // 設(shè)置數(shù)據(jù)庫緩存路徑 settings.setAppCacheEnabled(true); settings.setAppCachePath(cacheDirPath); // 設(shè)置是否使用viewport // false:加載頁面的寬度總是使用webview // true:由頁面的viewport標(biāo)簽決定 settings.setUseWideViewPort(true); settings.setLoadWithOverviewMode(true); settings.setAllowContentAccess(true); // 設(shè)置是否支持文件訪問 settings.setAllowFileAccess(true); // 設(shè)置縮放 settings.setSupportZoom(true); // 設(shè)置是否開啟內(nèi)置縮放機(jī)制 settings.setBuiltInZoomControls(true); // 設(shè)置開啟內(nèi)置縮放機(jī)制后是否顯示縮放控件 settings.setDisplayZoomControls(true); // 設(shè)置是否支持保存表單數(shù)據(jù) settings.setSaveFormData(true); // 設(shè)置webView的底層布局算法 settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); } @Override public void onBackPressed() { if (webView.canGoBack()) { webView.goBack(); } else { super.onBackPressed(); } } }
完成上面后還需在
AndroidManifest.xml
中添加如下節(jié)點(diǎn)<!-- 網(wǎng)頁WebView --> <activity android:name=".session.activity.WebViewActivity" android:screenOrientation="portrait" />
再創(chuàng)建圖片加載工具類
ImageLoader.java
砸讳,用于顯示圖片
com.netease.nim.demo.common.imageView.ImageLoader
public class ImageLoader { public static void onLoadImage(final String imageUrl, final LoadImageListener loadImageListener) { final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { loadImageListener.onLoadImage((Bitmap) msg.obj, null); } }; new Thread(new Runnable() { @Override public void run() { try { URL url = new URL(imageUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); InputStream is = conn.getInputStream(); Bitmap bitmap = BitmapFactory.decodeStream(is); is.close(); Message msg = new Message(); msg.obj = bitmap; handler.sendMessage(msg); } catch (IOException e) { e.printStackTrace(); } } @Override protected void finalize() throws Throwable { super.finalize(); } }).start(); } public interface LoadImageListener { public void onLoadImage(Bitmap bitmap, String bitmapPath); } }
注冊使用自定義的消息類型
在
SessionListFragment.java
中的getDigestOfAttachment
函數(shù)中添加以下代碼@Override public String getDigestOfAttachment(RecentContact recentContact, MsgAttachment attachment) { // 設(shè)置自定義消息的摘要消息琢融,展示在最近聯(lián)系人列表的消息縮略欄上 // 當(dāng)然,你也可以自定義一些內(nèi)建消息的縮略語簿寂,例如圖片漾抬,語音,音視頻會話等常遂,自定義的縮略語會被優(yōu)先使用纳令。 if (attachment instanceof GuessAttachment) { GuessAttachment guess = (GuessAttachment) attachment; return guess.getValue().getDesc(); } else if (attachment instanceof RTSAttachment) { return "[白板]"; } else if (attachment instanceof StickerAttachment) { return "[貼圖]"; } else if (attachment instanceof SnapChatAttachment) { return "[閱后即焚]"; } else if (attachment instanceof LinkAttachment) { // 添加顯示自定義的內(nèi)容 return "[圖文鏈接]"; } return null; }
另外我們自定義的消息應(yīng)該禁止用戶長按轉(zhuǎn)發(fā)給其他人的功能,編輯
SessionHelper.java
克胳,修改registerMsgForwardFilter
函數(shù)平绩,還需注冊我們自定義的消息類型解析顯示,修改registerViewHolders
函數(shù)漠另,添加自定義的注冊類捏雌。private static void registerMsgForwardFilter() { NimUIKit.setMsgForwardFilter(new MsgForwardFilter() { @Override public boolean shouldIgnore(IMMessage message) { if (message.getDirect() == MsgDirectionEnum.In && (message.getAttachStatus() == AttachStatusEnum.transferring || message.getAttachStatus() == AttachStatusEnum.fail)) { // 接收到的消息,附件沒有下載成功笆搓,不允許轉(zhuǎn)發(fā) return true; } else if (message.getMsgType() == MsgTypeEnum.custom && message.getAttachment() != null && (message.getAttachment() instanceof SnapChatAttachment || message.getAttachment() instanceof RTSAttachment // 添加此處判斷 || message.getAttachment() instanceof LinkAttachment)) { // 白板消息和閱后即焚消息腹忽,紅包消息,圖文鏈接消息 不允許轉(zhuǎn)發(fā) return true; } else if (message.getMsgType() == MsgTypeEnum.robot && message.getAttachment() != null && ((RobotAttachment) message.getAttachment()).isRobotSend()) { return true; // 如果是機(jī)器人發(fā)送的消息 不支持轉(zhuǎn)發(fā) } return false; } }); } //... private static void registerViewHolders() { NimUIKit.registerMsgItemViewHolder(FileAttachment.class, MsgViewHolderFile.class); NimUIKit.registerMsgItemViewHolder(AVChatAttachment.class, MsgViewHolderAVChat.class); NimUIKit.registerMsgItemViewHolder(GuessAttachment.class, MsgViewHolderGuess.class); NimUIKit.registerMsgItemViewHolder(CustomAttachment.class, MsgViewHolderDefCustom.class); NimUIKit.registerMsgItemViewHolder(StickerAttachment.class, MsgViewHolderSticker.class); NimUIKit.registerMsgItemViewHolder(SnapChatAttachment.class, MsgViewHolderSnapChat.class); NimUIKit.registerMsgItemViewHolder(RTSAttachment.class, MsgViewHolderRTS.class); // 注冊圖文類型消息 NimUIKit.registerMsgItemViewHolder(LinkAttachment.class, MsgViewHolderLink.class); NimUIKit.registerTipMsgViewHolder(MsgViewHolderTip.class); }
到此處砚作,已經(jīng)完成了所有操作了窘奏。但不知道是否有效,因此我們希望能夠通過一種方式方便自己調(diào)試使用葫录。
添加測試按鈕着裹,方便調(diào)試
在
com.netease.nim.demo.session.action
創(chuàng)建LinkAction.java
public class LinkAction extends BaseAction { public LinkAction() { // R.string.input_panel_textimg 需要在 strings.xml 中添加 // <string name="input_panel_textimg">圖文消息</string> super(R.drawable.message_plus_guess_selector, R.string.input_panel_textimg); } @Override public void onClick() { LinkAttachment attachment = new LinkAttachment(); attachment.setTitle("暖冬季歡樂送"); attachment.setDescribe("家具滿1000元減100元再返100元現(xiàn)金券!點(diǎn)擊查看詳情面粮!"); attachment.setLinkUrl("點(diǎn)擊消息后跳轉(zhuǎn)的地址"); attachment.setImageUrl("顯示的圖片url"); // 以下 "圖文鏈接:" + attachment.getTitle() 用來顯示app消息推送時(shí)少孝,圖片顯示的內(nèi)容。 IMMessage message = MessageBuilder.createCustomMessage(getAccount(), getSessionType(), "圖文鏈接:" + attachment.getTitle(), attachment); sendMessage(message); } }
在 SessionHelper.java 中添加如下代碼熬苍,將上面創(chuàng)建的按鈕功能注冊到消息面板中
// 定制化單聊界面稍走。如果使用默認(rèn)界面,返回null即可 private static SessionCustomization getP2pCustomization() { //... actions.add(new RTSAction()); actions.add(new SnapChatAction()); actions.add(new GuessAction()); actions.add(new FileAction()); // 添加圖文鏈接消息測試按鈕 actions.add(new LinkAction()); //... }
添加完成后柴底,運(yùn)行代碼在單聊窗口中婿脸,點(diǎn)擊右下角的 + 會發(fā)現(xiàn)多了個(gè) 圖文消息按鈕,點(diǎn)擊即可發(fā)送圖文消息內(nèi)容柄驻,還可以嘗試注釋掉
LinkAction.java
中的attachment.setDescribe("...");
和attachment.setImageUrl("...");
然后再測試狐树,發(fā)送之后和點(diǎn)擊圖文消息鏈接后如下。尾篇
到此抑钟,云信android端的擴(kuò)展自定義消息已經(jīng)完成涯曲。當(dāng)然,這只是android的顯示正常了在塔,其他如web幻件,iOS,pc等客戶端收到此類的消息心俗,顯示有問題傲武,也是需要擴(kuò)展調(diào)整的。此篇文章其他端的文章我會陸續(xù)更新城榛,如果有需要的同學(xué)可以關(guān)注下揪利。
以下附上其他版本擴(kuò)展的鏈接
最后編輯于 :?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來章贞,“玉大人祥绞,你說我怎么就攤上這事⊙枷蓿” “怎么了蜕径?”我有些... 文/不壞的土叔 我叫張陵,是天一觀的道長败京。 經(jīng)常有香客問我兜喻,道長,這世上最難降的妖魔是什么赡麦? 我笑而不... 正文 為了忘掉前任朴皆,我火速辦了婚禮,結(jié)果婚禮上隧甚,老公的妹妹穿的比我還像新娘车荔。我一直安慰自己,他們只是感情好戚扳,可當(dāng)我... 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著族吻,像睡著了一般帽借。 火紅的嫁衣襯著肌膚如雪珠增。 梳的紋絲不亂的頭發(fā)上,一... 文/蒼蘭香墨 我猛地睜開眼梦皮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了桃焕?” 一聲冷哼從身側(cè)響起剑肯,我... 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎观堂,沒想到半個(gè)月后让网,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)... 正文 獨(dú)居荒郊野嶺守林人離奇死亡师痕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日... 正文 我和宋清朗相戀三年溃睹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胰坟。... 正文 年R本政府宣布狠裹,位于F島的核電站虽界,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏涛菠。R本人自食惡果不足惜莉御,卻給世界環(huán)境... 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望俗冻。 院中可真熱鬧礁叔,春花似錦、人聲如沸迄薄。這莊子的主人今日做“春日... 文/蒼蘭香墨 我抬頭看了看天上的太陽讥蔽。三九已至涣易,卻和暖如春画机,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背新症。 一陣腳步聲響... 正文 我出身青樓荚醒,卻偏偏與公主長得像,于是被迫代替她去往敵國和親隆嗅。 傳聞我的和親對象是個(gè)殘疾皇子界阁,可洞房花燭夜當(dāng)晚...